Add CLI to interact with Diun through gRPC (#382)

Add simple CLI to interact with Diun through gRPC
Create image and notif proto services
Compile and validate protos through a dedicated Dockerfile and bake target
Implement proto definitions
Move server as `serve` command
New commands `image` and `notif`
Refactor command line usage doc
Better CLI error handling
Tools build constraint to manage tools deps through go modules
Add upgrade notes

Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax
2021-05-26 18:18:10 +02:00
committed by GitHub
parent 1318a007e3
commit 1115234010
44 changed files with 2376 additions and 343 deletions

View File

@@ -25,6 +25,21 @@ env:
GHCR_SLUG: ghcr.io/crazy-max/diun GHCR_SLUG: ghcr.io/crazy-max/diun
jobs: jobs:
validate:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
-
name: Validate
uses: docker/bake-action@v1
with:
targets: validate
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -49,7 +64,9 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [ test ] needs:
- validate
- test
steps: steps:
- -
name: Checkout name: Checkout

View File

@@ -1,28 +0,0 @@
name: validate
on:
push:
branches:
- 'master'
tags:
- 'v*'
- 'dockerfile/*'
pull_request:
branches:
- 'master'
jobs:
validate:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
-
name: Validate
uses: docker/bake-action@v1
with:
targets: validate

View File

@@ -18,7 +18,7 @@ RUN --mount=type=bind,target=/src,rw \
--dist "/out" \ --dist "/out" \
--hooks="go mod tidy" \ --hooks="go mod tidy" \
--hooks="go mod download" \ --hooks="go mod download" \
--main="./cmd/main.go" \ --main="./cmd" \
--ldflags="-s -w -X 'main.version={{.Version}}'" \ --ldflags="-s -w -X 'main.version={{.Version}}'" \
--files="CHANGELOG.md" \ --files="CHANGELOG.md" \
--files="LICENSE" \ --files="LICENSE" \
@@ -44,3 +44,4 @@ ENV PROFILER_PATH="/profiler" \
VOLUME [ "/data" ] VOLUME [ "/data" ]
ENTRYPOINT [ "diun" ] ENTRYPOINT [ "diun" ]
CMD [ "serve" ]

34
cmd/cli.go Normal file
View File

@@ -0,0 +1,34 @@
package main
import (
"github.com/crazy-max/diun/v4/pb"
"google.golang.org/grpc"
)
// CliHandler is a cli interface
type CliHandler interface {
BeforeApply() error
}
// CliGlobals holds globals cli attributes
type CliGlobals struct {
CliHandler `kong:"-"`
conn *grpc.ClientConn `kong:"-"`
imageSvc pb.ImageServiceClient `kong:"-"`
notifSvc pb.NotifServiceClient `kong:"-"`
GRPCAuthority string `kong:"name='grpc-authority',default='127.0.0.1:42286',help='Link to Diun gRPC API.'"`
}
// BeforeApply is a hook that run cli cmd are executed.
func (s *CliGlobals) BeforeApply() (err error) {
s.conn, err = grpc.Dial(s.GRPCAuthority, grpc.WithInsecure())
if err != nil {
return err
}
s.imageSvc = pb.NewImageServiceClient(s.conn)
s.notifSvc = pb.NewNotifServiceClient(s.conn)
return
}

131
cmd/image.go Normal file
View File

@@ -0,0 +1,131 @@
package main
import (
"context"
"fmt"
"os"
"sort"
"strings"
"time"
"unicode"
"github.com/crazy-max/diun/v4/pb"
"github.com/docker/go-units"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/tidwall/pretty"
"google.golang.org/protobuf/encoding/protojson"
)
// ImageCmd holds image command
type ImageCmd struct {
List ImageListCmd `kong:"cmd,default='1',help='List images in database.'"`
Inspect ImageInspectCmd `kong:"cmd,help='Display information of an image in database.'"`
Remove ImageRemoveCmd `kong:"cmd,help='Remove an image manifest from database.'"`
//Prune ImagePruneCmd `kong:"cmd,help='Remove unused manifests from the database.'"`
}
// ImageListCmd holds image list command
type ImageListCmd struct {
CliGlobals
Raw bool `kong:"name='raw',default='false',help='JSON output.'"`
}
func (s *ImageListCmd) Run(ctx *Context) error {
defer s.conn.Close()
il, err := s.imageSvc.ImageList(context.Background(), &pb.ImageListRequest{})
if err != nil {
return err
}
sort.Slice(il.Images, func(i, j int) bool {
return strings.Map(unicode.ToUpper, il.Images[i].Name) < strings.Map(unicode.ToUpper, il.Images[j].Name)
})
if s.Raw {
b, _ := protojson.Marshal(il)
fmt.Println(string(pretty.Pretty(b)))
return nil
}
t := table.NewWriter()
t.SetOutputMirror(os.Stdout)
t.AppendHeader(table.Row{"Name", "Manifests Count", "Latest Tag", "Latest Created", "Latest Digest"})
for _, image := range il.Images {
t.AppendRow(table.Row{image.Name, image.ManifestsCount, image.Latest.Tag, image.Latest.Created.AsTime().Format(time.RFC3339), image.Latest.Digest})
}
t.AppendFooter(table.Row{"Total", len(il.Images)})
t.Render()
return nil
}
// ImageInspectCmd holds image inspect command
type ImageInspectCmd struct {
CliGlobals
Image string `kong:"name='image',required,help='Image to inspect.'"`
Raw bool `kong:"name='raw',default='false',help='JSON output.'"`
}
func (s *ImageInspectCmd) Run(ctx *Context) error {
defer s.conn.Close()
ii, err := s.imageSvc.ImageInspect(context.Background(), &pb.ImageInspectRequest{
Name: s.Image,
})
if err != nil {
return err
}
sort.Slice(ii.Image.Manifests, func(i, j int) bool {
return ii.Image.Manifests[i].Created.AsTime().After(ii.Image.Manifests[j].Created.AsTime())
})
if s.Raw {
b, _ := protojson.Marshal(ii)
fmt.Println(string(pretty.Pretty(b)))
return nil
}
t := table.NewWriter()
t.SetOutputMirror(os.Stdout)
t.AppendHeader(table.Row{"Tag", "Created", "Digest"})
for _, image := range ii.Image.Manifests {
t.AppendRow(table.Row{image.Tag, image.Created.AsTime().Format(time.RFC3339), image.Digest})
}
t.AppendFooter(table.Row{"Total", len(ii.Image.Manifests)})
t.Render()
return nil
}
// ImageRemoveCmd holds image remove command
type ImageRemoveCmd struct {
CliGlobals
Image string `kong:"name='image',required,help='Image to remove.'"`
All bool `kong:"name='all',default='false',help='Remove all manifests from the database.'"`
}
func (s *ImageRemoveCmd) Run(ctx *Context) error {
defer s.conn.Close()
removed, err := s.imageSvc.ImageRemove(context.Background(), &pb.ImageRemoveRequest{
Name: s.Image,
})
if err != nil {
return err
}
t := table.NewWriter()
t.SetOutputMirror(os.Stdout)
t.AppendHeader(table.Row{"Tag", "Created", "Digest", "Size"})
var totalSize int64
for _, image := range removed.Manifests {
t.AppendRow(table.Row{image.Tag, image.Created.AsTime().Format(time.RFC3339), image.Digest, units.HumanSize(float64(image.Size))})
totalSize += image.Size
}
t.AppendFooter(table.Row{"Total", fmt.Sprintf("%d (%s)", len(removed.Manifests), units.HumanSize(float64(totalSize)))})
t.Render()
return nil
}

View File

@@ -3,48 +3,48 @@ package main
import ( import (
"fmt" "fmt"
"os" "os"
"os/signal"
"path"
"runtime" "runtime"
"strings" "strings"
"syscall"
_ "time/tzdata" _ "time/tzdata"
"github.com/alecthomas/kong" "github.com/alecthomas/kong"
"github.com/crazy-max/diun/v4/internal/app"
"github.com/crazy-max/diun/v4/internal/config"
"github.com/crazy-max/diun/v4/internal/logging"
"github.com/crazy-max/diun/v4/internal/model" "github.com/crazy-max/diun/v4/internal/model"
"github.com/pkg/profile"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
var ( var (
diun *app.Diun
cli model.Cli
version = "dev" version = "dev"
meta = model.Meta{ cli struct {
ID: "diun", Version kong.VersionFlag
Name: "Diun", Serve ServeCmd `kong:"cmd,help='Starts Diun server.'"`
Desc: "Docker image update notifier", Image ImageCmd `kong:"cmd,help='Manage image manifests.'"`
URL: "https://github.com/crazy-max/diun", Notif NotifCmd `kong:"cmd,help='Manage notifications.'"`
Logo: "https://raw.githubusercontent.com/crazy-max/diun/master/.res/diun.png",
Author: "CrazyMax",
} }
) )
type Context struct {
Meta model.Meta
}
func main() { func main() {
var err error var err error
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())
meta.Version = version meta := model.Meta{
ID: "diun",
Name: "Diun",
Desc: "Docker image update notifier",
URL: "https://github.com/crazy-max/diun",
Logo: "https://raw.githubusercontent.com/crazy-max/diun/master/.res/diun.png",
Author: "CrazyMax",
Version: version,
}
meta.UserAgent = fmt.Sprintf("%s/%s go/%s %s", meta.ID, meta.Version, runtime.Version()[2:], strings.Title(runtime.GOOS)) meta.UserAgent = fmt.Sprintf("%s/%s go/%s %s", meta.ID, meta.Version, runtime.Version()[2:], strings.Title(runtime.GOOS))
if meta.Hostname, err = os.Hostname(); err != nil { if meta.Hostname, err = os.Hostname(); err != nil {
log.Fatal().Err(err).Msg("Cannot resolve hostname") log.Fatal().Err(err).Msg("Cannot resolve hostname")
} }
// Parse command line ctx := kong.Parse(&cli,
_ = kong.Parse(&cli,
kong.Name(meta.ID), kong.Name(meta.ID),
kong.Description(fmt.Sprintf("%s. More info: %s", meta.Desc, meta.URL)), kong.Description(fmt.Sprintf("%s. More info: %s", meta.Desc, meta.URL)),
kong.UsageOnError(), kong.UsageOnError(),
@@ -56,69 +56,5 @@ func main() {
Summary: true, Summary: true,
})) }))
// Init ctx.FatalIfErrorf(ctx.Run(&Context{Meta: meta}))
logging.Configure(&cli)
log.Info().Str("version", version).Msgf("Starting %s", meta.Name)
// Handle os signals
channel := make(chan os.Signal)
signal.Notify(channel, os.Interrupt, syscall.SIGTERM)
go func() {
sig := <-channel
diun.Close()
log.Warn().Msgf("Caught signal %v", sig)
os.Exit(0)
}()
// Load configuration
cfg, err := config.Load(cli)
if err != nil {
log.Fatal().Err(err).Msg("Cannot load configuration")
}
log.Debug().Msg(cfg.String())
// Profiler
if len(cli.Profiler) > 0 && len(cli.ProfilerPath) > 0 {
profilerPath := path.Clean(cli.ProfilerPath)
if err = os.MkdirAll(profilerPath, os.ModePerm); err != nil {
log.Fatal().Err(err).Msg("Cannot create profiler folder")
}
profilePath := profile.ProfilePath(profilerPath)
switch cli.Profiler {
case "cpu":
defer profile.Start(profile.CPUProfile, profilePath).Stop()
case "mem":
defer profile.Start(profile.MemProfile, profilePath).Stop()
case "alloc":
defer profile.Start(profile.MemProfileAllocs, profilePath).Stop()
case "heap":
defer profile.Start(profile.MemProfileHeap, profilePath).Stop()
case "routines":
defer profile.Start(profile.GoroutineProfile, profilePath).Stop()
case "mutex":
defer profile.Start(profile.MutexProfile, profilePath).Stop()
case "threads":
defer profile.Start(profile.ThreadcreationProfile, profilePath).Stop()
case "block":
defer profile.Start(profile.BlockProfile, profilePath).Stop()
default:
log.Fatal().Msgf("Unknown profiler: %s", cli.Profiler)
}
}
// Init
if diun, err = app.New(meta, cli, cfg); err != nil {
log.Fatal().Err(err).Msgf("Cannot initialize %s", meta.Name)
}
// Test notif
if cli.TestNotif {
diun.TestNotif()
return
}
// Start
if err = diun.Start(); err != nil {
log.Fatal().Err(err).Msgf("Cannot start %s", meta.Name)
}
} }

30
cmd/notif.go Normal file
View File

@@ -0,0 +1,30 @@
package main
import (
"context"
"fmt"
"github.com/crazy-max/diun/v4/pb"
)
// NotifCmd holds notif command
type NotifCmd struct {
Test NotifTestCmd `kong:"cmd,help='Test notification settings.'"`
}
// NotifTestCmd holds notif test command
type NotifTestCmd struct {
CliGlobals
}
func (s *NotifTestCmd) Run(ctx *Context) error {
defer s.conn.Close()
nt, err := s.notifSvc.NotifTest(context.Background(), &pb.NotifTestRequest{})
if err != nil {
return err
}
fmt.Println(nt.Message)
return nil
}

99
cmd/serve.go Normal file
View File

@@ -0,0 +1,99 @@
package main
import (
"os"
"os/signal"
"path"
"syscall"
"github.com/crazy-max/diun/v4/internal/app"
"github.com/crazy-max/diun/v4/internal/config"
"github.com/crazy-max/diun/v4/internal/logging"
"github.com/pkg/profile"
"github.com/rs/zerolog/log"
)
// ServeCmd holds serve command args and flags
type ServeCmd struct {
Cfgfile string `kong:"name='config',env='CONFIG',help='Diun configuration file.'"`
ProfilerPath string `kong:"name='profiler-path',env='PROFILER_PATH',help='Base path where profiling files are written.'"`
Profiler string `kong:"name='profiler',env='PROFILER',help='Profiler to use.'"`
LogLevel string `kong:"name='log-level',env='LOG_LEVEL',default='info',help='Set log level.'"`
LogJSON bool `kong:"name='log-json',env='LOG_JSON',default='false',help='Enable JSON logging output.'"`
LogCaller bool `kong:"name='log-caller',env='LOG_CALLER',default='false',help='Add file:line of the caller to log output.'"`
LogNoColor bool `kong:"name='log-nocolor',env='LOG_NOCOLOR',default='false',help='Disables the colorized output.'"`
GRPCAuthority string `kong:"name='grpc-authority',env='GRPC_AUTHORITY',default=':42286',help='Address used to expose the gRPC server.'"`
}
func (s *ServeCmd) Run(ctx *Context) error {
var diun *app.Diun
// Logging
logging.Configure(logging.Options{
LogLevel: s.LogLevel,
LogJSON: s.LogJSON,
LogCaller: s.LogCaller,
LogNoColor: s.LogNoColor,
})
log.Info().Str("version", version).Msgf("Starting %s", ctx.Meta.Name)
// Handle os signals
channel := make(chan os.Signal)
signal.Notify(channel, os.Interrupt, syscall.SIGTERM)
go func() {
sig := <-channel
diun.Close()
log.Warn().Msgf("Caught signal %v", sig)
os.Exit(0)
}()
// Load configuration
cfg, err := config.Load(s.Cfgfile)
if err != nil {
log.Fatal().Err(err).Msg("Cannot load configuration")
}
log.Debug().Msg(cfg.String())
// Profiler
if len(s.Profiler) > 0 && len(s.ProfilerPath) > 0 {
profilerPath := path.Clean(s.ProfilerPath)
if err = os.MkdirAll(profilerPath, os.ModePerm); err != nil {
log.Fatal().Err(err).Msg("Cannot create profiler folder")
}
profilePath := profile.ProfilePath(profilerPath)
switch s.Profiler {
case "cpu":
defer profile.Start(profile.CPUProfile, profilePath).Stop()
case "mem":
defer profile.Start(profile.MemProfile, profilePath).Stop()
case "alloc":
defer profile.Start(profile.MemProfileAllocs, profilePath).Stop()
case "heap":
defer profile.Start(profile.MemProfileHeap, profilePath).Stop()
case "routines":
defer profile.Start(profile.GoroutineProfile, profilePath).Stop()
case "mutex":
defer profile.Start(profile.MutexProfile, profilePath).Stop()
case "threads":
defer profile.Start(profile.ThreadcreationProfile, profilePath).Stop()
case "block":
defer profile.Start(profile.BlockProfile, profilePath).Stop()
default:
log.Fatal().Msgf("Unknown profiler: %s", s.Profiler)
}
}
// Init
diun, err = app.New(ctx.Meta, cfg, s.GRPCAuthority)
if err != nil {
log.Fatal().Err(err).Msgf("Cannot initialize %s", ctx.Meta.Name)
}
// Start
err = diun.Start()
if err != nil {
log.Fatal().Err(err).Msgf("Cannot start %s", ctx.Meta.Name)
}
return nil
}

View File

@@ -9,6 +9,17 @@ target "go-version" {
} }
} }
// protoc version
variable "PROTOC_VERSION" {
default = "3.17.0"
}
target "protoc-version" {
args = {
PROTOC_VERSION = PROTOC_VERSION
}
}
// GitHub reference as defined in GitHub Actions (eg. refs/head/master)) // GitHub reference as defined in GitHub Actions (eg. refs/head/master))
variable "GITHUB_REF" { variable "GITHUB_REF" {
default = "" default = ""
@@ -30,7 +41,7 @@ group "default" {
} }
group "validate" { group "validate" {
targets = ["lint", "vendor-validate"] targets = ["lint", "vendor-validate", "gen-validate"]
} }
target "lint" { target "lint" {
@@ -52,6 +63,19 @@ target "vendor-update" {
output = ["."] output = ["."]
} }
target "gen-validate" {
inherits = ["go-version", "protoc-version"]
dockerfile = "./hack/gen.Dockerfile"
target = "validate"
}
target "gen-update" {
inherits = ["go-version", "protoc-version"]
dockerfile = "./hack/gen.Dockerfile"
target = "update"
output = ["."]
}
target "test" { target "test" {
inherits = ["go-version"] inherits = ["go-version"]
dockerfile = "./hack/test.Dockerfile" dockerfile = "./hack/test.Dockerfile"

View File

@@ -22,7 +22,7 @@ At startup, Diun searches for a file named `diun.yml` (or `diun.yaml`) in:
* `$HOME/.config/` * `$HOME/.config/`
* `.` _(the working directory)_ * `.` _(the working directory)_
You can override this using the [`--config` flag or `CONFIG` env var](../usage/cli.md). You can override this using the [`--config` flag or `CONFIG` env var with `serve` command](../usage/command-line.md#serve).
??? example "diun.yml" ??? example "diun.yml"
```yaml ```yaml

View File

@@ -20,13 +20,11 @@ regopts:
passwordFile: /run/secrets/password passwordFile: /run/secrets/password
``` ```
`myregistry` will be used as a `name` selector (default) if referenced by its [name](#name). * `myregistry` will be used as a `name` selector (default) if referenced by its [name](#name).
* `docker.io` will be used as an `image` selector. If an image is on DockerHub (`docker.io` domain), this registry
`docker.io` will be used as an `image` selector. If an image is on DockerHub (`docker.io` domain), this registry options will options will be selected if not referenced as a `regopt` name.
be selected if not referenced as a `regopt` name. * `docker.io/crazymax` will be used as an `image` selector. If an image is on DockerHub and in `crazymax` namespace,
this registry options will be selected if not referenced as a `regopt` name.
`docker.io/crazymax` will be used as an `image` selector. If an image is on DockerHub and in `crazymax` namespace, this registry options will
be selected if not referenced as a `regopt` name.
## Configuration ## Configuration

View File

@@ -60,7 +60,7 @@ Send notification at the very first analysis of an image. (default `false`)
### `compareDigest` ### `compareDigest`
Compare the digest of an image with the registry before downloading the image manifest. It is strongly Compare the digest of an image with the registry before downloading the image manifest. It is strongly
recommended to leave this value at `true`, especially with [Docker Hub which imposes a rate-limit](../faq.md#docker-hub-rate-limits) recommended leaving this value at `true`, especially with [Docker Hub which imposes a rate-limit](../faq.md#docker-hub-rate-limits)
on image pull. (default `true`) on image pull. (default `true`)
!!! example "Config file" !!! example "Config file"
@@ -74,7 +74,7 @@ on image pull. (default `true`)
### `healthchecks` ### `healthchecks`
Healthchecks allows to monitor Diun watcher by sending start and success notification Healthchecks allows monitoring Diun watcher by sending start and success notification
events to [healthchecks.io](https://healthchecks.io/). events to [healthchecks.io](https://healthchecks.io/).
!!! tip !!! tip

View File

@@ -14,16 +14,16 @@ watch:
## Test notifications ## Test notifications
Through the [command line](usage/cli.md) with: Through the [command line](usage/command-line.md#notif-test) with:
```shell ```shell
diun --config ./diun.yml --test-notif diun notif test
``` ```
Or within a container: Or within a container:
```shell ```shell
docker-compose exec diun diun --test-notif docker-compose exec diun diun notif test
``` ```
## field docker|swarm uses unsupported type: invalid ## field docker|swarm uses unsupported type: invalid
@@ -127,7 +127,8 @@ Or you can tweak the [`schedule` setting](config/watch.md#schedule) with somethi
## Profiling ## Profiling
Diun provides a simple way to manage runtime/pprof profiling through [`--profiler-path` and `--profiler` flags](usage/cli.md#options): Diun provides a simple way to manage runtime/pprof profiling through the
[`--profiler-path` and `--profiler` flags with `serve` command](usage/command-line.md#serve):
```yaml ```yaml
version: "3.5" version: "3.5"

View File

@@ -25,8 +25,8 @@ And extract diun:
wget -qO- {{ config.repo_url }}releases/download/v{{ git.tag | trim('v') }}/diun_{{ git.tag | trim('v') }}_linux_x86_64.tar.gz | tar -zxvf - diun wget -qO- {{ config.repo_url }}releases/download/v{{ git.tag | trim('v') }}/diun_{{ git.tag | trim('v') }}_linux_x86_64.tar.gz | tar -zxvf - diun
``` ```
After getting the binary, it can be tested with [`./diun --help`](../usage/cli.md) command and moved to a permanent After getting the binary, it can be tested with [`./diun --help`](../usage/command-line.md#global-options) command
location. and moved to a permanent location.
## Server configuration ## Server configuration

View File

@@ -233,7 +233,8 @@ Following the transposition of the configuration into environment variables, the
is no longer loaded by default in the official Docker image. is no longer loaded by default in the official Docker image.
If you want to load a configuration file through the Docker image you will have to declare the If you want to load a configuration file through the Docker image you will have to declare the
[`CONFIG` environment variable](../usage/cli.md#environment-variables) pointing to the assigned configuration file: [`CONFIG` environment variable with `serve` command](../usage/command-line.md#serve) pointing to the assigned
configuration file:
!!! tip !!! tip
This is no longer required since version 4.2.0. Now configuration file can be loaded from This is no longer required since version 4.2.0. Now configuration file can be loaded from

View File

@@ -0,0 +1,15 @@
# Diun v4.0 to v4.17
## New CLI
CLI has changed since 4.17 and includes [`serve` command](../usage/command-line.md#serve) to start Diun:
!!! example "v4.0"
```shell
diun --config diun.yml
```
!!! example "v4.17"
```shell
diun serve --config diun.yml
```

View File

@@ -1,44 +0,0 @@
# Command Line
## Usage
```shell
diun [options]
```
## Options
```
$ diun --help
Usage: diun
Docker image update notifier. More info: https://github.com/crazy-max/diun
Flags:
-h, --help Show context-sensitive help.
--version
--config=STRING Diun configuration file ($CONFIG).
--profiler-path=STRING Base path where profiling files are written
($PROFILER_PATH).
--profiler=STRING Profiler to use ($PROFILER).
--log-level="info" Set log level ($LOG_LEVEL).
--log-json Enable JSON logging output ($LOG_JSON).
--log-caller Add file:line of the caller to log output
($LOG_CALLER).
--log-nocolor Disables the colorized output ($LOG_NOCOLOR).
--test-notif Test notification settings.
```
## Environment variables
Following environment variables can be used in place:
| Name | Default | Description |
|--------------------|---------------|---------------|
| `CONFIG` | | Diun configuration file |
| `PROFILER_PATH` | | Base path where profiling files are written |
| `PROFILER` | | [Profiler](../faq.md#profiling) to use |
| `LOG_LEVEL` | `info` | Log level output |
| `LOG_JSON` | `false` | Enable JSON logging output |
| `LOG_CALLER` | `false` | Enable to add `file:line` of the caller |
| `LOG_NOCOLOR` | `false` | Disables the colorized output |

124
docs/usage/command-line.md Normal file
View File

@@ -0,0 +1,124 @@
# Command Line
## Usage
```shell
diun [global options] command [command or global options] [arguments...]
```
## Global options
All global options can be placed at the command level.
* `--help`, `-h`: Show context-sensitive help.
* `--version`: Show version and exit.
## Commands
### `serve`
Starts Diun server.
* `--config <path>`: Diun configuration file
* `--profiler-path <path>`: Base path where profiling files are written
* `--profiler <string>`: Profiler to use
* `--log-level <string>`: Set log level (default `info`)
* `--log-json`: Enable JSON logging output
* `--log-caller`: Add `file:line` of the caller to log output
* `--log-nocolor`: Disables the colorized output
* `--grpc-authority <string>`: Address used to expose the gRPC server (default `:42286`)
Examples:
```shell
diun serve --config diun.yml --log-level debug
```
Following environment variables can also be used in place:
| Name | Default | Description |
|--------------------|---------------|---------------|
| `CONFIG` | | Diun configuration file |
| `PROFILER_PATH` | | Base path where profiling files are written |
| `PROFILER` | | [Profiler](../faq.md#profiling) to use |
| `LOG_LEVEL` | `info` | Log level output |
| `LOG_JSON` | `false` | Enable JSON logging output |
| `LOG_CALLER` | `false` | Enable to add `file:line` of the caller |
| `LOG_NOCOLOR` | `false` | Disables the colorized output |
| `GRPC_AUTHORITY` | `:42286` | Address used to expose the gRPC server |
### `image list`
!!! note
Diun needs to be started through [`serve`](#serve) command to be able to use this command.
List images in database.
* `--raw`: JSON output
* `--grpc-authority <string>`: Link to Diun gRPC API (default `127.0.0.1:42286`)
Examples:
```shell
diun image list
```
```shell
diun image list --raw
```
### `image inspect`
!!! note
Diun needs to be started through [`serve`](#serve) command to be able to use this command.
Display information of an image in database.
* `--image`: Image to inspect (**required**)
* `--raw`: JSON output
* `--grpc-authority <string>`: Link to Diun gRPC API (default `127.0.0.1:42286`)
Examples:
```shell
diun image inspect alpine
```
```shell
diun image inspect drone/drone --raw
```
### `image remove`
!!! note
Diun needs to be started through [`serve`](#serve) command to be able to use this command.
Remove an image manifest from database.
* `--image`: Image to remove (**required**)
* `--grpc-authority <string>`: Link to Diun gRPC API (default `127.0.0.1:42286`)
Examples:
```shell
diun image remove alpine:latest
```
```shell
diun image inspect drone/drone
```
!!! warning
All manifest for an image will be removed if no tag is specified
### `notif test`
!!! note
Diun needs to be started through [`serve`](#serve) command to be able to use this command.
Test notification settings.
* `--grpc-authority <string>`: Link to Diun gRPC API (default `127.0.0.1:42286`)
Examples:
```shell
diun notif test
```

8
go.mod
View File

@@ -1,6 +1,6 @@
module github.com/crazy-max/diun/v4 module github.com/crazy-max/diun/v4
go 1.15 go 1.16
require ( require (
github.com/alecthomas/kong v0.2.16 github.com/alecthomas/kong v0.2.16
@@ -11,6 +11,7 @@ require (
github.com/crazy-max/gonfig v0.4.0 github.com/crazy-max/gonfig v0.4.0
github.com/docker/docker v20.10.6+incompatible github.com/docker/docker v20.10.6+incompatible
github.com/docker/go-connections v0.4.0 github.com/docker/go-connections v0.4.0
github.com/docker/go-units v0.4.0
github.com/eclipse/paho.mqtt.golang v1.3.3 github.com/eclipse/paho.mqtt.golang v1.3.3
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df
github.com/go-playground/validator/v10 v10.5.0 github.com/go-playground/validator/v10 v10.5.0
@@ -18,6 +19,7 @@ require (
github.com/gregdel/pushover v0.0.0-20201104094836-ddbe0c1d3a38 github.com/gregdel/pushover v0.0.0-20201104094836-ddbe0c1d3a38
github.com/hako/durafmt v0.0.0-20190612201238-650ed9f29a84 github.com/hako/durafmt v0.0.0-20190612201238-650ed9f29a84
github.com/imdario/mergo v0.3.12 github.com/imdario/mergo v0.3.12
github.com/jedib0t/go-pretty/v6 v6.2.1
github.com/matcornic/hermes/v2 v2.1.0 github.com/matcornic/hermes/v2 v2.1.0
github.com/matrix-org/gomatrix v0.0.0-20200501121722-e5578b12c752 github.com/matrix-org/gomatrix v0.0.0-20200501121722-e5578b12c752
github.com/microcosm-cc/bluemonday v1.0.9 github.com/microcosm-cc/bluemonday v1.0.9
@@ -35,7 +37,11 @@ require (
github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
github.com/technoweenie/multipartstreamer v1.0.1 // indirect github.com/technoweenie/multipartstreamer v1.0.1 // indirect
github.com/tidwall/pretty v1.1.0
go.etcd.io/bbolt v1.3.5 go.etcd.io/bbolt v1.3.5
google.golang.org/grpc v1.37.0
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0
google.golang.org/protobuf v1.26.0
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0

30
go.sum
View File

@@ -298,8 +298,9 @@ github.com/cilium/ebpf v0.2.0 h1:Fv93L3KKckEcEHR3oApXVzyBTDA8WAm6VXhPE00N3f8=
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f h1:WBZRG4aNOuI15bLRrCgN8fCq8E5Xuty6jGbmSNEvSsU=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 h1:cqQfy1jclcSy/FwLjemeg3SR1yaINm74aQyupQ0Bl8M=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58 h1:hHWif/4GirK3P5uvCyyj941XSVIQDzuJhbEguCICdPE= github.com/codahale/hdrhistogram v0.0.0-20160425231609-f8ad88b59a58 h1:hHWif/4GirK3P5uvCyyj941XSVIQDzuJhbEguCICdPE=
@@ -458,8 +459,9 @@ github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4 h1:rEvIZUSZ3fx39WIi3JkQqQBitGwpELBIYWeBVh6wn+E=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d h1:QyzYnTnPE15SQyUeqU6qLbWxMkwyAyu+vGksa0b7j00=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
@@ -478,6 +480,8 @@ github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHqu
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fzipp/gocyclo v0.3.1 h1:A9UeX3HJSXTBzvHzhqoYVuE0eAhe+aM8XBCCwsPMZOc=
github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E=
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7 h1:LofdAjjjqCSXMwLGgOgnE+rdPuvX9DxCqaHwKy7i/ko= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7 h1:LofdAjjjqCSXMwLGgOgnE+rdPuvX9DxCqaHwKy7i/ko=
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@@ -616,8 +620,9 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@@ -667,8 +672,9 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-containerregistry v0.0.0-20191010200024-a3d713f9b7f8/go.mod h1:KyKXa9ciM8+lgMXwOVsXi7UxGrsf9mM61Mzs+xKUrKE= github.com/google/go-containerregistry v0.0.0-20191010200024-a3d713f9b7f8/go.mod h1:KyKXa9ciM8+lgMXwOVsXi7UxGrsf9mM61Mzs+xKUrKE=
github.com/google/go-containerregistry v0.1.2 h1:YjFNKqxzWUVZND8d4ItF9wuYlE75WQfECE7yKX/Nu3o= github.com/google/go-containerregistry v0.1.2 h1:YjFNKqxzWUVZND8d4ItF9wuYlE75WQfECE7yKX/Nu3o=
github.com/google/go-containerregistry v0.1.2/go.mod h1:GPivBPgdAyd2SU+vf6EpsgOtWDuPqjW0hJZt4rNdTZ4= github.com/google/go-containerregistry v0.1.2/go.mod h1:GPivBPgdAyd2SU+vf6EpsgOtWDuPqjW0hJZt4rNdTZ4=
@@ -856,6 +862,8 @@ github.com/jarcoal/httpmock v1.0.5 h1:cHtVEcTxRSX4J0je7mWPfc9BpDpqzXSJ5HbymZmyHc
github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0 h1:xqgexXAGQgY3HAjNPSaCqn5Aahbo5TKsmhp8VRfr1iQ= github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0 h1:xqgexXAGQgY3HAjNPSaCqn5Aahbo5TKsmhp8VRfr1iQ=
github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
github.com/jedib0t/go-pretty/v6 v6.2.1 h1:O/3XdNfyWSyVLLIt1EeDhfP8AhNMjtBSh0MuZ4frg6U=
github.com/jedib0t/go-pretty/v6 v6.2.1/go.mod h1:+nE9fyyHGil+PuISTCrp7avEdo6bqoMwqZnuiK2r2a0=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1 h1:ujPKutqRlJtcfWk6toYVYagwra7HQHbXOaS171b4Tg8= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1 h1:ujPKutqRlJtcfWk6toYVYagwra7HQHbXOaS171b4Tg8=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a h1:GmsqmapfzSJkm28dhRoHz2tLRbJmqhU86IPgBtN3mmk= github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a h1:GmsqmapfzSJkm28dhRoHz2tLRbJmqhU86IPgBtN3mmk=
@@ -977,6 +985,7 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg= github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
@@ -1152,6 +1161,7 @@ github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/profile v1.5.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= github.com/pkg/profile v1.5.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
github.com/pkg/profile v1.6.0 h1:hUDfIISABYI59DyeB3OTay/HxSRwTQ8rB/H83k6r5dM= github.com/pkg/profile v1.6.0 h1:hUDfIISABYI59DyeB3OTay/HxSRwTQ8rB/H83k6r5dM=
github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
@@ -1348,6 +1358,8 @@ github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6
github.com/tetafro/godot v0.3.7/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0= github.com/tetafro/godot v0.3.7/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0=
github.com/tetafro/godot v0.4.2 h1:Dib7un+rYJFUi8vN0Bk6EHheKy6fv6ZzFURHw75g6m8= github.com/tetafro/godot v0.4.2 h1:Dib7un+rYJFUi8vN0Bk6EHheKy6fv6ZzFURHw75g6m8=
github.com/tetafro/godot v0.4.2/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0= github.com/tetafro/godot v0.4.2/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0=
github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8=
github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
github.com/timakin/bodyclose v0.0.0-20200424151742-cb6215831a94 h1:ig99OeTyDwQWhPe2iw9lwfQVF1KB3Q4fpP3X7/2VBG8= github.com/timakin/bodyclose v0.0.0-20200424151742-cb6215831a94 h1:ig99OeTyDwQWhPe2iw9lwfQVF1KB3Q4fpP3X7/2VBG8=
github.com/timakin/bodyclose v0.0.0-20200424151742-cb6215831a94/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= github.com/timakin/bodyclose v0.0.0-20200424151742-cb6215831a94/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
@@ -1611,6 +1623,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1868,8 +1881,11 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.37.0 h1:uSZWeQJX5j11bIQ4AJoj+McDBo29cY1MCoC1wO3ts+c=
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -1879,8 +1895,10 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo= gopkg.in/airbrake/gobrake.v2 v2.0.9 h1:7z2uVWwn7oVeeugY1DtlPAy5H+KYgB1KeKTnqjNatLo=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=

40
hack/gen.Dockerfile Normal file
View File

@@ -0,0 +1,40 @@
# syntax=docker/dockerfile:1.2
ARG GO_VERSION
ARG PROTOC_VERSION
ARG GLIBC_VERSION=2.33-r0
FROM golang:${GO_VERSION}-alpine AS base
ARG GLIBC_VERSION
RUN apk add --no-cache curl file git unzip \
&& curl -sSL "https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub" -o "/etc/apk/keys/sgerrand.rsa.pub" \
&& curl -sSL "https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VERSION}/glibc-${GLIBC_VERSION}.apk" -o "glibc.apk" \
&& apk add glibc.apk \
&& rm /etc/apk/keys/sgerrand.rsa.pub glibc.apk
ARG PROTOC_VERSION
RUN curl -sSL "https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip" -o "protoc.zip" \
&& unzip "protoc.zip" -d "/usr/local" \
&& protoc --version \
&& rm "protoc.zip"
WORKDIR /src
FROM base AS gomod
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/go/pkg/mod \
go mod tidy && go mod download && go install -v $(sed -n -e 's|^\s*_\s*"\(.*\)".*$|\1| p' tools.go)
FROM gomod AS generate
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/go/pkg/mod \
go generate ./... && mkdir /out && cp -Rf pb /out
FROM scratch AS update
COPY --from=generate /out /
FROM generate AS validate
RUN --mount=type=bind,target=.,rw \
git add -A && cp -rf /out/* .; \
if [ -n "$(git status --porcelain)" ]; then \
echo >&2 'ERROR: Generate result differs. Please update with "docker buildx bake gen-update"'; \
git status --porcelain; \
exit 1; \
fi

View File

@@ -8,6 +8,7 @@ import (
"github.com/crazy-max/diun/v4/internal/config" "github.com/crazy-max/diun/v4/internal/config"
"github.com/crazy-max/diun/v4/internal/db" "github.com/crazy-max/diun/v4/internal/db"
"github.com/crazy-max/diun/v4/internal/grpc"
"github.com/crazy-max/diun/v4/internal/logging" "github.com/crazy-max/diun/v4/internal/logging"
"github.com/crazy-max/diun/v4/internal/model" "github.com/crazy-max/diun/v4/internal/model"
"github.com/crazy-max/diun/v4/internal/notif" "github.com/crazy-max/diun/v4/internal/notif"
@@ -16,7 +17,6 @@ import (
filePrd "github.com/crazy-max/diun/v4/internal/provider/file" filePrd "github.com/crazy-max/diun/v4/internal/provider/file"
kubernetesPrd "github.com/crazy-max/diun/v4/internal/provider/kubernetes" kubernetesPrd "github.com/crazy-max/diun/v4/internal/provider/kubernetes"
swarmPrd "github.com/crazy-max/diun/v4/internal/provider/swarm" swarmPrd "github.com/crazy-max/diun/v4/internal/provider/swarm"
"github.com/crazy-max/diun/v4/pkg/registry"
"github.com/crazy-max/gohealthchecks" "github.com/crazy-max/gohealthchecks"
"github.com/hako/durafmt" "github.com/hako/durafmt"
"github.com/panjf2000/ants/v2" "github.com/panjf2000/ants/v2"
@@ -27,12 +27,15 @@ import (
// Diun represents an active diun object // Diun represents an active diun object
type Diun struct { type Diun struct {
meta model.Meta meta model.Meta
cfg *config.Config cfg *config.Config
db *db.Client
grpc *grpc.Client
hc *gohealthchecks.Client
notif *notif.Client
cron *cron.Cron cron *cron.Cron
db *db.Client
hc *gohealthchecks.Client
notif *notif.Client
jobID cron.EntryID jobID cron.EntryID
locker uint32 locker uint32
pool *ants.PoolWithFunc pool *ants.PoolWithFunc
@@ -40,7 +43,7 @@ type Diun struct {
} }
// New creates new diun instance // New creates new diun instance
func New(meta model.Meta, cli model.Cli, cfg *config.Config) (*Diun, error) { func New(meta model.Meta, cfg *config.Config, grpcAuthority string) (*Diun, error) {
var err error var err error
diun := &Diun{ diun := &Diun{
@@ -56,11 +59,14 @@ func New(meta model.Meta, cli model.Cli, cfg *config.Config) (*Diun, error) {
return nil, err return nil, err
} }
if !cli.TestNotif { diun.db, err = db.New(*cfg.Db)
diun.db, err = db.New(*cfg.Db) if err != nil {
if err != nil { return nil, err
return nil, err }
}
diun.grpc, err = grpc.New(grpcAuthority, diun.db, diun.notif)
if err != nil {
return nil, err
} }
if cfg.Watch.Healthchecks != nil { if cfg.Watch.Healthchecks != nil {
@@ -89,6 +95,13 @@ func (di *Diun) Start() error {
return err return err
} }
// Start GRPC server
go func() {
if err := di.grpc.Start(); err != nil {
log.Fatal().Err(err).Msg("Failed to start GRPC server")
}
}()
// Run on startup // Run on startup
di.Run() di.Run()
@@ -157,7 +170,7 @@ func (di *Diun) Run() {
di.createJob(job) di.createJob(job)
} }
// Dokcerfile provider // Dockerfile provider
for _, job := range dockerfilePrd.New(di.cfg.Providers.Dockerfile).ListJob() { for _, job := range dockerfilePrd.New(di.cfg.Providers.Dockerfile).ListJob() {
di.createJob(job) di.createJob(job)
} }
@@ -178,51 +191,8 @@ func (di *Diun) Close() {
if di.cron != nil { if di.cron != nil {
di.cron.Stop() di.cron.Stop()
} }
di.grpc.Stop()
if err := di.db.Close(); err != nil { if err := di.db.Close(); err != nil {
log.Warn().Err(err).Msg("Cannot close database") log.Warn().Err(err).Msg("Cannot close database")
} }
} }
// TestNotif test the notification settings
func (di *Diun) TestNotif() {
createdAt, _ := time.Parse("2006-01-02T15:04:05Z", "2020-03-26T12:23:56Z")
image, _ := registry.ParseImage(registry.ParseImageOptions{
Name: "diun/testnotif:latest",
})
image.HubLink = ""
log.Info().Msg("Testing notification settings...")
di.notif.Send(model.NotifEntry{
Status: "new",
Provider: "file",
Image: image,
Manifest: registry.Manifest{
Name: "diun/testnotif",
Tag: "latest",
MIMEType: "application/vnd.docker.distribution.manifest.list.v2+json",
Digest: "sha256:216e3ae7de4ca8b553eb11ef7abda00651e79e537e85c46108284e5e91673e01",
Created: &createdAt,
DockerVersion: "",
Labels: map[string]string{
"maintainer": "CrazyMax",
"org.label-schema.build-date": "2020-03-26T12:23:56Z",
"org.label-schema.description": "Docker image update notifier",
"org.label-schema.name": "Diun",
"org.label-schema.schema-version": "1.0",
"org.label-schema.url": "https://github.com/crazy-max/diun",
"org.label-schema.vcs-ref": "e13f097c",
"org.label-schema.vcs-url": "https://github.com/crazy-max/diun",
"org.label-schema.vendor": "CrazyMax",
"org.label-schema.version": "x.x.x",
},
Layers: []string{
"sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819",
"sha256:166c6f165b73185ede72415d780538a55c0c8e854bd177925bc007193e5b0d1b",
"sha256:e05682efa9cc9d6239b2b9252fe0dc1e58d6e1585679733bb94a6549d49e9b10",
"sha256:c6a5bfed445b3ed7e85523cd73c6532ac9f9b72bb588ca728fd5b33987ca6538",
"sha256:df2140efb8abeb727ef0b27ff158b7010a7941eb1cfdade505f510a6e1eaf016",
},
Platform: "linux/amd64",
},
})
}

View File

@@ -22,14 +22,14 @@ type Config struct {
} }
// Load returns Config struct // Load returns Config struct
func Load(cli model.Cli) (*Config, error) { func Load(config string) (*Config, error) {
cfg := Config{ cfg := Config{
Db: (&model.Db{}).GetDefaults(), Db: (&model.Db{}).GetDefaults(),
Watch: (&model.Watch{}).GetDefaults(), Watch: (&model.Watch{}).GetDefaults(),
} }
fileLoader := gonfig.NewFileLoader(gonfig.FileLoaderConfig{ fileLoader := gonfig.NewFileLoader(gonfig.FileLoaderConfig{
Filename: cli.Cfgfile, Filename: config,
Finder: gonfig.Finder{ Finder: gonfig.Finder{
BasePaths: []string{"/etc/diun/diun", "$XDG_CONFIG_HOME/diun", "$HOME/.config/diun", "./diun"}, BasePaths: []string{"/etc/diun/diun", "$XDG_CONFIG_HOME/diun", "$HOME/.config/diun", "./diun"},
Extensions: []string{"yaml", "yml"}, Extensions: []string{"yaml", "yml"},
@@ -54,14 +54,14 @@ func Load(cli model.Cli) (*Config, error) {
log.Info().Msgf("Configuration loaded from %d environment variable(s)", len(envLoader.GetVars())) log.Info().Msgf("Configuration loaded from %d environment variable(s)", len(envLoader.GetVars()))
} }
if err := cfg.validate(cli); err != nil { if err := cfg.validate(); err != nil {
return nil, err return nil, err
} }
return &cfg, nil return &cfg, nil
} }
func (cfg *Config) validate(cli model.Cli) error { func (cfg *Config) validate() error {
if len(cfg.Db.Path) > 0 { if len(cfg.Db.Path) > 0 {
if err := os.MkdirAll(path.Dir(cfg.Db.Path), os.ModePerm); err != nil { if err := os.MkdirAll(path.Dir(cfg.Db.Path), os.ModePerm); err != nil {
return errors.Wrap(err, "Cannot create database destination folder") return errors.Wrap(err, "Cannot create database destination folder")
@@ -72,11 +72,7 @@ func (cfg *Config) validate(cli model.Cli) error {
return errors.New("Healthchecks UUID is required") return errors.New("Healthchecks UUID is required")
} }
if cfg.Notif == nil && cli.TestNotif { if cfg.Providers == nil {
return errors.New("At least one notifier is required")
}
if cfg.Providers == nil && !cli.TestNotif {
return errors.New("At least one provider is required") return errors.New("At least one provider is required")
} }

View File

@@ -18,55 +18,33 @@ import (
func TestLoadFile(t *testing.T) { func TestLoadFile(t *testing.T) {
cases := []struct { cases := []struct {
name string name string
cli model.Cli cfg string
wantData *config.Config wantData *config.Config
wantErr bool wantErr bool
}{ }{
{ {
name: "Failed on non-existing file", name: "Failed on non-existing file",
cli: model.Cli{ cfg: "",
TestNotif: false,
},
wantErr: true, wantErr: true,
}, },
{ {
name: "Fail on wrong file format", name: "Fail on wrong file format",
cli: model.Cli{ cfg: "./fixtures/config.invalid.yml",
Cfgfile: "./fixtures/config.invalid.yml",
TestNotif: false,
},
wantErr: true, wantErr: true,
}, },
{ {
name: "Fail on no UUID for Healthchecks", name: "Fail on no UUID for Healthchecks",
cli: model.Cli{ cfg: "./fixtures/config.err.hc.yml",
Cfgfile: "./fixtures/config.err.hc.yml",
TestNotif: false,
},
wantErr: true, wantErr: true,
}, },
{ {
name: "Fail on no notifier if test notif", name: "Fail on no provider",
cli: model.Cli{ cfg: "./fixtures/config.err.provider.yml",
Cfgfile: "./fixtures/config.err.notif.yml",
TestNotif: true,
},
wantErr: true,
},
{
name: "Fail on no provider",
cli: model.Cli{
Cfgfile: "./fixtures/config.err.provider.yml",
TestNotif: false,
},
wantErr: true, wantErr: true,
}, },
{ {
name: "Success", name: "Success",
cli: model.Cli{ cfg: "./fixtures/config.test.yml",
Cfgfile: "./fixtures/config.test.yml",
TestNotif: false,
},
wantData: &config.Config{ wantData: &config.Config{
Db: &model.Db{ Db: &model.Db{
Path: "diun.db", Path: "diun.db",
@@ -218,7 +196,7 @@ func TestLoadFile(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) cfg, err := config.Load(tt.cfg)
if tt.wantErr { if tt.wantErr {
require.Error(t, err) require.Error(t, err)
return return
@@ -237,7 +215,7 @@ func TestLoadEnv(t *testing.T) {
testCases := []struct { testCases := []struct {
desc string desc string
cli model.Cli cfg string
environ []string environ []string
expected interface{} expected interface{}
wantErr bool wantErr bool
@@ -365,7 +343,7 @@ func TestLoadEnv(t *testing.T) {
} }
} }
cfg, err := config.Load(tt.cli) cfg, err := config.Load(tt.cfg)
if tt.wantErr { if tt.wantErr {
require.Error(t, err) require.Error(t, err)
return return
@@ -382,17 +360,14 @@ func TestLoadMixed(t *testing.T) {
testCases := []struct { testCases := []struct {
desc string desc string
cli model.Cli cfg string
environ []string environ []string
expected interface{} expected interface{}
wantErr bool wantErr bool
}{ }{
{ {
desc: "env vars and invalid file", desc: "env vars and invalid file",
cli: model.Cli{ cfg: "./fixtures/config.invalid.yml",
Cfgfile: "./fixtures/config.invalid.yml",
TestNotif: false,
},
environ: []string{ environ: []string{
"DIUN_PROVIDERS_DOCKER=true", "DIUN_PROVIDERS_DOCKER=true",
}, },
@@ -401,10 +376,7 @@ func TestLoadMixed(t *testing.T) {
}, },
{ {
desc: "docker provider (file) and notif mails (envs)", desc: "docker provider (file) and notif mails (envs)",
cli: model.Cli{ cfg: "./fixtures/config.docker.yml",
Cfgfile: "./fixtures/config.docker.yml",
TestNotif: false,
},
environ: []string{ environ: []string{
"DIUN_NOTIF_MAIL_HOST=127.0.0.1", "DIUN_NOTIF_MAIL_HOST=127.0.0.1",
"DIUN_NOTIF_MAIL_PORT=25", "DIUN_NOTIF_MAIL_PORT=25",
@@ -441,10 +413,7 @@ func TestLoadMixed(t *testing.T) {
}, },
{ {
desc: "file provider and notif webhook env override", desc: "file provider and notif webhook env override",
cli: model.Cli{ cfg: "./fixtures/config.file.yml",
Cfgfile: "./fixtures/config.file.yml",
TestNotif: false,
},
environ: []string{ environ: []string{
"DIUN_NOTIF_WEBHOOK_ENDPOINT=http://webhook.foo.com/sd54qad89azd5a", "DIUN_NOTIF_WEBHOOK_ENDPOINT=http://webhook.foo.com/sd54qad89azd5a",
"DIUN_NOTIF_WEBHOOK_HEADERS_AUTHORIZATION=Token78910", "DIUN_NOTIF_WEBHOOK_HEADERS_AUTHORIZATION=Token78910",
@@ -488,7 +457,7 @@ func TestLoadMixed(t *testing.T) {
} }
} }
cfg, err := config.Load(tt.cli) cfg, err := config.Load(tt.cfg)
if tt.wantErr { if tt.wantErr {
require.Error(t, err) require.Error(t, err)
return return
@@ -503,19 +472,16 @@ func TestLoadMixed(t *testing.T) {
func TestValidation(t *testing.T) { func TestValidation(t *testing.T) {
cases := []struct { cases := []struct {
name string name string
cli model.Cli cfg string
}{ }{
{ {
name: "Success", name: "Success",
cli: model.Cli{ cfg: "./fixtures/config.validate.yml",
Cfgfile: "./fixtures/config.validate.yml",
TestNotif: false,
},
}, },
} }
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) cfg, err := config.Load(tt.cfg)
require.NoError(t, err) require.NoError(t, err)
dec, err := env.Encode("DIUN_", cfg) dec, err := env.Encode("DIUN_", cfg)

View File

@@ -1,2 +0,0 @@
providers:
docker: {}

View File

@@ -3,6 +3,7 @@ package db
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt"
"github.com/crazy-max/diun/v4/pkg/registry" "github.com/crazy-max/diun/v4/pkg/registry"
bolt "go.etcd.io/bbolt" bolt "go.etcd.io/bbolt"
@@ -25,6 +26,25 @@ func (c *Client) First(image registry.Image) (bool, error) {
return !found, err return !found, err
} }
// ListManifest return a list of Docker images manifests
func (c *Client) ListManifest() ([]registry.Manifest, error) {
var manifests []registry.Manifest
err := c.View(func(tx *bolt.Tx) error {
c := tx.Bucket([]byte(bucketManifest)).Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
var manifest registry.Manifest
if err := json.Unmarshal(v, &manifest); err != nil {
return err
}
manifests = append(manifests, manifest)
}
return nil
})
return manifests, err
}
// GetManifest returns Docker image manifest // GetManifest returns Docker image manifest
func (c *Client) GetManifest(image registry.Image) (registry.Manifest, error) { func (c *Client) GetManifest(image registry.Image) (registry.Manifest, error) {
var manifest registry.Manifest var manifest registry.Manifest
@@ -43,11 +63,37 @@ func (c *Client) GetManifest(image registry.Image) (registry.Manifest, error) {
// PutManifest add Docker image manifest in db // PutManifest add Docker image manifest in db
func (c *Client) PutManifest(image registry.Image, manifest registry.Manifest) error { func (c *Client) PutManifest(image registry.Image, manifest registry.Manifest) error {
entryBytes, _ := json.Marshal(manifest) entryBytes, _ := json.Marshal(manifest)
return c.Update(func(tx *bolt.Tx) error {
err := c.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(bucketManifest)) b := tx.Bucket([]byte(bucketManifest))
return b.Put([]byte(image.String()), entryBytes) return b.Put([]byte(image.String()), entryBytes)
}) })
}
return err
// DeleteManifest deletes a Docker image manifest
func (c *Client) DeleteManifest(manifest registry.Manifest) error {
return c.Update(func(tx *bolt.Tx) error {
return tx.Bucket([]byte(bucketManifest)).Delete([]byte(fmt.Sprintf("%s:%s", manifest.Name, manifest.Tag)))
})
}
// ListImage return a list of Docker images with their linked manifests
func (c *Client) ListImage() (map[string][]registry.Manifest, error) {
images := make(map[string][]registry.Manifest)
err := c.View(func(tx *bolt.Tx) error {
c := tx.Bucket([]byte(bucketManifest)).Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
var manifest registry.Manifest
if err := json.Unmarshal(v, &manifest); err != nil {
return err
}
if _, ok := images[manifest.Name]; !ok {
images[manifest.Name] = []registry.Manifest{}
}
images[manifest.Name] = append(images[manifest.Name], manifest)
}
return nil
})
return images, err
} }

View File

@@ -29,11 +29,8 @@ func (c *Client) ReadMetadata() error {
// WriteMetadata writes db metadata // WriteMetadata writes db metadata
func (c *Client) WriteMetadata(metadata Metadata) error { func (c *Client) WriteMetadata(metadata Metadata) error {
entryBytes, _ := json.Marshal(metadata) entryBytes, _ := json.Marshal(metadata)
return c.Update(func(tx *bolt.Tx) error {
err := c.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(bucketMetadata)) b := tx.Bucket([]byte(bucketMetadata))
return b.Put([]byte(metadataKey), entryBytes) return b.Put([]byte(metadataKey), entryBytes)
}) })
return err
} }

View File

@@ -75,9 +75,5 @@ func (c *Client) migration2() error {
} }
} }
if err := tx.Commit(); err != nil { return tx.Commit()
return err
}
return nil
} }

58
internal/grpc/client.go Normal file
View File

@@ -0,0 +1,58 @@
package grpc
import (
"net"
"github.com/crazy-max/diun/v4/internal/db"
grpclogger "github.com/crazy-max/diun/v4/internal/grpc/logger"
"github.com/crazy-max/diun/v4/internal/notif"
"github.com/crazy-max/diun/v4/pb"
"github.com/pkg/errors"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"google.golang.org/grpc"
)
// Client represents an active grpc object
type Client struct {
server *grpc.Server
authority string
db *db.Client
notif *notif.Client
pb.UnimplementedImageServiceServer
pb.UnimplementedNotifServiceServer
}
// New creates a new grpc instance
func New(authority string, db *db.Client, notif *notif.Client) (*Client, error) {
grpclogger.SetGrpcLogger(log.Level(zerolog.ErrorLevel))
c := &Client{
authority: authority,
db: db,
notif: notif,
}
c.server = grpc.NewServer()
pb.RegisterImageServiceServer(c.server, c)
pb.RegisterNotifServiceServer(c.server, c)
return c, nil
}
// Start runs the grpc server
func (c *Client) Start() error {
var err error
lis, err := net.Listen("tcp", c.authority)
if err != nil {
return errors.Wrap(err, "Cannot create gRPC listener")
}
return c.server.Serve(lis)
}
// Stop stops the grpc server
func (c *Client) Stop() {
c.server.GracefulStop()
}

123
internal/grpc/image.go Normal file
View File

@@ -0,0 +1,123 @@
package grpc
import (
"context"
"encoding/json"
"fmt"
"github.com/containers/image/v5/docker/reference"
"github.com/crazy-max/diun/v4/pb"
"google.golang.org/protobuf/types/known/timestamppb"
)
func (c *Client) ImageList(ctx context.Context, request *pb.ImageListRequest) (*pb.ImageListResponse, error) {
images, err := c.db.ListImage()
if err != nil {
return nil, err
}
var ilr []*pb.ImageListResponse_Image
for name, manifests := range images {
latest := &manifests[0]
for _, manifest := range manifests {
if manifest.Created.After(*latest.Created) {
latest = &manifest
}
}
ilr = append(ilr, &pb.ImageListResponse_Image{
Name: name,
ManifestsCount: int64(len(manifests)),
Latest: &pb.Manifest{
Tag: latest.Tag,
MimeType: latest.MIMEType,
Digest: latest.Digest.String(),
Created: timestamppb.New(*latest.Created),
Labels: latest.Labels,
Platform: latest.Platform,
},
})
}
return &pb.ImageListResponse{
Images: ilr,
}, nil
}
func (c *Client) ImageInspect(ctx context.Context, request *pb.ImageInspectRequest) (*pb.ImageInspectResponse, error) {
ref, err := reference.ParseNormalizedNamed(request.Name)
if err != nil {
return nil, err
}
images, err := c.db.ListImage()
if err != nil {
return nil, err
}
if _, ok := images[ref.Name()]; !ok {
return nil, fmt.Errorf("%s not found in database", ref.Name())
}
iir := &pb.ImageInspectResponse_Image{
Name: ref.Name(),
Manifests: []*pb.Manifest{},
}
for _, manifest := range images[ref.Name()] {
iir.Manifests = append(iir.Manifests, &pb.Manifest{
Tag: manifest.Tag,
MimeType: manifest.MIMEType,
Digest: manifest.Digest.String(),
Created: timestamppb.New(*manifest.Created),
Labels: manifest.Labels,
Platform: manifest.Platform,
})
}
return &pb.ImageInspectResponse{
Image: iir,
}, nil
}
func (c *Client) ImageRemove(ctx context.Context, request *pb.ImageRemoveRequest) (*pb.ImageRemoveResponse, error) {
ref, err := reference.ParseNormalizedNamed(request.Name)
if err != nil {
return nil, err
}
images, err := c.db.ListImage()
if err != nil {
return nil, err
}
if _, ok := images[ref.Name()]; !ok {
return nil, fmt.Errorf("%s not found in database", ref.Name())
}
var tag string
if tagged, ok := ref.(reference.Tagged); ok {
tag = tagged.Tag()
}
var removed []*pb.Manifest
for _, manifest := range images[ref.Name()] {
if len(tag) == 0 || manifest.Tag == tag {
if err = c.db.DeleteManifest(manifest); err != nil {
return nil, err
}
b, _ := json.Marshal(manifest)
removed = append(removed, &pb.Manifest{
Tag: manifest.Tag,
MimeType: manifest.MIMEType,
Digest: manifest.Digest.String(),
Created: timestamppb.New(*manifest.Created),
Labels: manifest.Labels,
Platform: manifest.Platform,
Size: int64(len(b)),
})
}
}
return &pb.ImageRemoveResponse{
Manifests: removed,
}, nil
}

View File

@@ -0,0 +1,94 @@
package logger
import (
"fmt"
"github.com/rs/zerolog"
"google.golang.org/grpc/grpclog"
)
func SetGrpcLogger(logger zerolog.Logger) {
grpclog.SetLoggerV2(wrap(logger))
}
func wrap(l zerolog.Logger) *bridge {
return &bridge{l}
}
type bridge struct {
zerolog.Logger
}
func (b *bridge) Info(args ...interface{}) {
b.Logger.Info().Msg(fmt.Sprint(args...))
}
func (b *bridge) Infoln(args ...interface{}) {
b.Logger.Info().Msg(fmt.Sprint(args...))
}
func (b *bridge) Infof(format string, args ...interface{}) {
b.Logger.Info().Msgf(format, args...)
}
func (b *bridge) Warning(args ...interface{}) {
b.Logger.Warn().Msg(fmt.Sprint(args...))
}
func (b *bridge) Warningln(args ...interface{}) {
b.Logger.Warn().Msg(fmt.Sprint(args...))
}
func (b *bridge) Warningf(format string, args ...interface{}) {
b.Logger.Warn().Msgf(format, args...)
}
func (b *bridge) Error(args ...interface{}) {
b.Logger.Error().Msg(fmt.Sprint(args...))
}
func (b *bridge) Errorln(args ...interface{}) {
b.Logger.Error().Msg(fmt.Sprint(args...))
}
func (b *bridge) Errorf(format string, args ...interface{}) {
b.Logger.Error().Msgf(format, args...)
}
func (b *bridge) Fatal(args ...interface{}) {
b.Logger.Fatal().Msg(fmt.Sprint(args...))
}
func (b *bridge) Fatalln(args ...interface{}) {
b.Logger.Fatal().Msg(fmt.Sprint(args...))
}
func (b *bridge) Fatalf(format string, args ...interface{}) {
b.Logger.Fatal().Msgf(format, args...)
}
func (b *bridge) V(verbosity int) bool {
// verbosity values:
// 0 = info
// 1 = warning
// 2 = error
// 3 = fatal
switch b.GetLevel() {
case zerolog.PanicLevel:
return verbosity > 3
case zerolog.FatalLevel:
return verbosity == 3
case zerolog.ErrorLevel:
return verbosity == 2
case zerolog.WarnLevel:
return verbosity == 1
case zerolog.InfoLevel:
return verbosity == 0
case zerolog.DebugLevel:
return true
case zerolog.TraceLevel:
return true
default:
return false
}
}

72
internal/grpc/notif.go Normal file
View File

@@ -0,0 +1,72 @@
package grpc
import (
"context"
"fmt"
"strings"
"time"
"github.com/crazy-max/diun/v4/internal/model"
"github.com/crazy-max/diun/v4/pb"
"github.com/crazy-max/diun/v4/pkg/registry"
)
func (c *Client) NotifTest(ctx context.Context, request *pb.NotifTestRequest) (*pb.NotifTestResponse, error) {
createdAt, _ := time.Parse("2006-01-02T15:04:05Z", "2020-03-26T12:23:56Z")
image, _ := registry.ParseImage(registry.ParseImageOptions{
Name: "diun/testnotif:latest",
})
image.HubLink = ""
entry := model.NotifEntry{
Status: "new",
Provider: "file",
Image: image,
Manifest: registry.Manifest{
Name: "diun/testnotif",
Tag: "latest",
MIMEType: "application/vnd.docker.distribution.manifest.list.v2+json",
Digest: "sha256:216e3ae7de4ca8b553eb11ef7abda00651e79e537e85c46108284e5e91673e01",
Created: &createdAt,
DockerVersion: "",
Labels: map[string]string{
"maintainer": "CrazyMax",
"org.label-schema.build-date": "2020-03-26T12:23:56Z",
"org.label-schema.description": "Docker image update notifier",
"org.label-schema.name": "Diun",
"org.label-schema.schema-version": "1.0",
"org.label-schema.url": "https://github.com/crazy-max/diun",
"org.label-schema.vcs-ref": "e13f097c",
"org.label-schema.vcs-url": "https://github.com/crazy-max/diun",
"org.label-schema.vendor": "CrazyMax",
"org.label-schema.version": "x.x.x",
},
Layers: []string{
"sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819",
"sha256:166c6f165b73185ede72415d780538a55c0c8e854bd177925bc007193e5b0d1b",
"sha256:e05682efa9cc9d6239b2b9252fe0dc1e58d6e1585679733bb94a6549d49e9b10",
"sha256:c6a5bfed445b3ed7e85523cd73c6532ac9f9b72bb588ca728fd5b33987ca6538",
"sha256:df2140efb8abeb727ef0b27ff158b7010a7941eb1cfdade505f510a6e1eaf016",
},
Platform: "linux/amd64",
},
}
if len(c.notif.List()) == 0 {
return &pb.NotifTestResponse{
Message: "No notifier available",
}, nil
}
var sent []string
for _, n := range c.notif.List() {
if err := n.Send(entry); err != nil {
return nil, err
}
sent = append(sent, n.Name())
}
return &pb.NotifTestResponse{
Message: fmt.Sprintf("Notifcation sent for %s notifier(s)", strings.Join(sent, ", ")),
}, nil
}

View File

@@ -6,24 +6,30 @@ import (
"os" "os"
"time" "time"
"github.com/crazy-max/diun/v4/internal/model"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
type Options struct {
LogLevel string
LogJSON bool
LogCaller bool
LogNoColor bool
}
// Configure configures logger // Configure configures logger
func Configure(cli *model.Cli) { func Configure(opts Options) {
var err error var err error
var w io.Writer var w io.Writer
// Adds support for NO_COLOR. More info https://no-color.org/ // Adds support for NO_COLOR. More info https://no-color.org/
_, noColor := os.LookupEnv("NO_COLOR") _, noColor := os.LookupEnv("NO_COLOR")
if !cli.LogJSON { if !opts.LogJSON {
w = zerolog.ConsoleWriter{ w = zerolog.ConsoleWriter{
Out: os.Stdout, Out: os.Stdout,
NoColor: noColor || cli.LogNoColor, NoColor: noColor || opts.LogNoColor,
TimeFormat: time.RFC1123, TimeFormat: time.RFC1123,
} }
} else { } else {
@@ -31,20 +37,20 @@ func Configure(cli *model.Cli) {
} }
ctx := zerolog.New(w).With().Timestamp() ctx := zerolog.New(w).With().Timestamp()
if cli.LogCaller { if opts.LogCaller {
ctx = ctx.Caller() ctx = ctx.Caller()
} }
log.Logger = ctx.Logger() log.Logger = ctx.Logger()
logLevel, err := zerolog.ParseLevel(cli.LogLevel) logLevel, err := zerolog.ParseLevel(opts.LogLevel)
if err != nil { if err != nil {
log.Fatal().Err(err).Msgf("Unknown log level") log.Fatal().Err(err).Msgf("Unknown log level")
} else { } else {
zerolog.SetGlobalLevel(logLevel) zerolog.SetGlobalLevel(logLevel)
} }
logrusLevel, err := logrus.ParseLevel(cli.LogLevel) logrusLevel, err := logrus.ParseLevel(opts.LogLevel)
if err != nil { if err != nil {
log.Fatal().Err(err).Msgf("Unknown log level") log.Fatal().Err(err).Msgf("Unknown log level")
} else { } else {

View File

@@ -1,16 +0,0 @@
package model
import "github.com/alecthomas/kong"
// Cli holds command line args, flags and cmds
type Cli struct {
Version kong.VersionFlag
Cfgfile string `kong:"name='config',env='CONFIG',help='Diun configuration file.'"`
ProfilerPath string `kong:"name='profiler-path',env='PROFILER_PATH',help='Base path where profiling files are written.'"`
Profiler string `kong:"name='profiler',env='PROFILER',help='Profiler to use.'"`
LogLevel string `kong:"name='log-level',env='LOG_LEVEL',default='info',help='Set log level.'"`
LogJSON bool `kong:"name='log-json',env='LOG_JSON',default='false',help='Enable JSON logging output.'"`
LogCaller bool `kong:"name='log-caller',env='LOG_CALLER',default='false',help='Add file:line of the caller to log output.'"`
LogNoColor bool `kong:"name='log-nocolor',env='LOG_NOCOLOR',default='false',help='Disables the colorized output.'"`
TestNotif bool `kong:"name='test-notif',default='false',help='Test notification settings.'"`
}

View File

@@ -95,3 +95,8 @@ func (c *Client) Send(entry model.NotifEntry) {
} }
} }
} }
// List returns created notifiers
func (c *Client) List() []notifier.Notifier {
return c.notifiers
}

View File

@@ -90,7 +90,7 @@ nav:
- From binary: install/binary.md - From binary: install/binary.md
- Linux service: install/linux-service.md - Linux service: install/linux-service.md
- Usage: - Usage:
- Command line: usage/cli.md - Command line: usage/command-line.md
- Basic example: usage/basic-example.md - Basic example: usage/basic-example.md
- Configuration: - Configuration:
- Overview: config/index.md - Overview: config/index.md
@@ -125,6 +125,7 @@ nav:
- FAQ: faq.md - FAQ: faq.md
- Changelog: changelog.md - Changelog: changelog.md
- Migration: - Migration:
- Diun v4.0 to v4.17: migration/v4.0-to-v4.17.md
- Diun v3 to v4: migration/v3-to-v4.md - Diun v3 to v4: migration/v3-to-v4.md
- Diun v2 to v3: migration/v2-to-v3.md - Diun v2 to v3: migration/v2-to-v3.md
- Diun v1 to v2: migration/v1-to-v2.md - Diun v1 to v2: migration/v1-to-v2.md

3
pb/gen.go Normal file
View File

@@ -0,0 +1,3 @@
package pb
//go:generate protoc --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:. image.proto notif.proto

764
pb/image.pb.go Normal file
View File

@@ -0,0 +1,764 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.17.0
// source: image.proto
package pb
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Manifest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
MimeType string `protobuf:"bytes,2,opt,name=mime_type,json=mimeType,proto3" json:"mime_type,omitempty"`
Digest string `protobuf:"bytes,3,opt,name=digest,proto3" json:"digest,omitempty"`
Created *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=created,proto3" json:"created,omitempty"`
Labels map[string]string `protobuf:"bytes,5,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Platform string `protobuf:"bytes,6,opt,name=platform,proto3" json:"platform,omitempty"`
Size int64 `protobuf:"varint,7,opt,name=size,proto3" json:"size,omitempty"`
}
func (x *Manifest) Reset() {
*x = Manifest{}
if protoimpl.UnsafeEnabled {
mi := &file_image_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Manifest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Manifest) ProtoMessage() {}
func (x *Manifest) ProtoReflect() protoreflect.Message {
mi := &file_image_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Manifest.ProtoReflect.Descriptor instead.
func (*Manifest) Descriptor() ([]byte, []int) {
return file_image_proto_rawDescGZIP(), []int{0}
}
func (x *Manifest) GetTag() string {
if x != nil {
return x.Tag
}
return ""
}
func (x *Manifest) GetMimeType() string {
if x != nil {
return x.MimeType
}
return ""
}
func (x *Manifest) GetDigest() string {
if x != nil {
return x.Digest
}
return ""
}
func (x *Manifest) GetCreated() *timestamppb.Timestamp {
if x != nil {
return x.Created
}
return nil
}
func (x *Manifest) GetLabels() map[string]string {
if x != nil {
return x.Labels
}
return nil
}
func (x *Manifest) GetPlatform() string {
if x != nil {
return x.Platform
}
return ""
}
func (x *Manifest) GetSize() int64 {
if x != nil {
return x.Size
}
return 0
}
type ImageListRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ImageListRequest) Reset() {
*x = ImageListRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_image_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ImageListRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ImageListRequest) ProtoMessage() {}
func (x *ImageListRequest) ProtoReflect() protoreflect.Message {
mi := &file_image_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ImageListRequest.ProtoReflect.Descriptor instead.
func (*ImageListRequest) Descriptor() ([]byte, []int) {
return file_image_proto_rawDescGZIP(), []int{1}
}
type ImageListResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Images []*ImageListResponse_Image `protobuf:"bytes,1,rep,name=images,proto3" json:"images,omitempty"`
}
func (x *ImageListResponse) Reset() {
*x = ImageListResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_image_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ImageListResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ImageListResponse) ProtoMessage() {}
func (x *ImageListResponse) ProtoReflect() protoreflect.Message {
mi := &file_image_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ImageListResponse.ProtoReflect.Descriptor instead.
func (*ImageListResponse) Descriptor() ([]byte, []int) {
return file_image_proto_rawDescGZIP(), []int{2}
}
func (x *ImageListResponse) GetImages() []*ImageListResponse_Image {
if x != nil {
return x.Images
}
return nil
}
type ImageInspectRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
}
func (x *ImageInspectRequest) Reset() {
*x = ImageInspectRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_image_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ImageInspectRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ImageInspectRequest) ProtoMessage() {}
func (x *ImageInspectRequest) ProtoReflect() protoreflect.Message {
mi := &file_image_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ImageInspectRequest.ProtoReflect.Descriptor instead.
func (*ImageInspectRequest) Descriptor() ([]byte, []int) {
return file_image_proto_rawDescGZIP(), []int{3}
}
func (x *ImageInspectRequest) GetName() string {
if x != nil {
return x.Name
}
return ""
}
type ImageInspectResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Image *ImageInspectResponse_Image `protobuf:"bytes,1,opt,name=image,proto3" json:"image,omitempty"`
}
func (x *ImageInspectResponse) Reset() {
*x = ImageInspectResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_image_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ImageInspectResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ImageInspectResponse) ProtoMessage() {}
func (x *ImageInspectResponse) ProtoReflect() protoreflect.Message {
mi := &file_image_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ImageInspectResponse.ProtoReflect.Descriptor instead.
func (*ImageInspectResponse) Descriptor() ([]byte, []int) {
return file_image_proto_rawDescGZIP(), []int{4}
}
func (x *ImageInspectResponse) GetImage() *ImageInspectResponse_Image {
if x != nil {
return x.Image
}
return nil
}
type ImageRemoveRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
}
func (x *ImageRemoveRequest) Reset() {
*x = ImageRemoveRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_image_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ImageRemoveRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ImageRemoveRequest) ProtoMessage() {}
func (x *ImageRemoveRequest) ProtoReflect() protoreflect.Message {
mi := &file_image_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ImageRemoveRequest.ProtoReflect.Descriptor instead.
func (*ImageRemoveRequest) Descriptor() ([]byte, []int) {
return file_image_proto_rawDescGZIP(), []int{5}
}
func (x *ImageRemoveRequest) GetName() string {
if x != nil {
return x.Name
}
return ""
}
type ImageRemoveResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Manifests []*Manifest `protobuf:"bytes,1,rep,name=manifests,proto3" json:"manifests,omitempty"`
}
func (x *ImageRemoveResponse) Reset() {
*x = ImageRemoveResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_image_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ImageRemoveResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ImageRemoveResponse) ProtoMessage() {}
func (x *ImageRemoveResponse) ProtoReflect() protoreflect.Message {
mi := &file_image_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ImageRemoveResponse.ProtoReflect.Descriptor instead.
func (*ImageRemoveResponse) Descriptor() ([]byte, []int) {
return file_image_proto_rawDescGZIP(), []int{6}
}
func (x *ImageRemoveResponse) GetManifests() []*Manifest {
if x != nil {
return x.Manifests
}
return nil
}
type ImageListResponse_Image struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
ManifestsCount int64 `protobuf:"varint,2,opt,name=manifestsCount,proto3" json:"manifestsCount,omitempty"`
Latest *Manifest `protobuf:"bytes,3,opt,name=latest,proto3" json:"latest,omitempty"`
}
func (x *ImageListResponse_Image) Reset() {
*x = ImageListResponse_Image{}
if protoimpl.UnsafeEnabled {
mi := &file_image_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ImageListResponse_Image) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ImageListResponse_Image) ProtoMessage() {}
func (x *ImageListResponse_Image) ProtoReflect() protoreflect.Message {
mi := &file_image_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ImageListResponse_Image.ProtoReflect.Descriptor instead.
func (*ImageListResponse_Image) Descriptor() ([]byte, []int) {
return file_image_proto_rawDescGZIP(), []int{2, 0}
}
func (x *ImageListResponse_Image) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *ImageListResponse_Image) GetManifestsCount() int64 {
if x != nil {
return x.ManifestsCount
}
return 0
}
func (x *ImageListResponse_Image) GetLatest() *Manifest {
if x != nil {
return x.Latest
}
return nil
}
type ImageInspectResponse_Image struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Manifests []*Manifest `protobuf:"bytes,2,rep,name=manifests,proto3" json:"manifests,omitempty"`
}
func (x *ImageInspectResponse_Image) Reset() {
*x = ImageInspectResponse_Image{}
if protoimpl.UnsafeEnabled {
mi := &file_image_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ImageInspectResponse_Image) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ImageInspectResponse_Image) ProtoMessage() {}
func (x *ImageInspectResponse_Image) ProtoReflect() protoreflect.Message {
mi := &file_image_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ImageInspectResponse_Image.ProtoReflect.Descriptor instead.
func (*ImageInspectResponse_Image) Descriptor() ([]byte, []int) {
return file_image_proto_rawDescGZIP(), []int{4, 0}
}
func (x *ImageInspectResponse_Image) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *ImageInspectResponse_Image) GetManifests() []*Manifest {
if x != nil {
return x.Manifests
}
return nil
}
var File_image_proto protoreflect.FileDescriptor
var file_image_proto_rawDesc = []byte{
0x0a, 0x0b, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70,
0x62, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x22, 0xa4, 0x02, 0x0a, 0x08, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12,
0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x74, 0x61,
0x67, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6d, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x69, 0x6d, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16,
0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x34, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
0x61, 0x6d, 0x70, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x30, 0x0a, 0x06,
0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70,
0x62, 0x2e, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c,
0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x1a,
0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69,
0x7a, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x1a, 0x39,
0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x12, 0x0a, 0x10, 0x49, 0x6d, 0x61,
0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xb3, 0x01,
0x0a, 0x11, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x4c, 0x69,
0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65,
0x52, 0x06, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x1a, 0x69, 0x0a, 0x05, 0x49, 0x6d, 0x61, 0x67,
0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73,
0x74, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x6d,
0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x24, 0x0a,
0x06, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e,
0x70, 0x62, 0x2e, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x52, 0x06, 0x6c, 0x61, 0x74,
0x65, 0x73, 0x74, 0x22, 0x29, 0x0a, 0x13, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x73, 0x70,
0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61,
0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x95,
0x01, 0x0a, 0x14, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x61, 0x67,
0x65, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x1a, 0x47, 0x0a,
0x05, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x09, 0x6d, 0x61,
0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e,
0x70, 0x62, 0x2e, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x52, 0x09, 0x6d, 0x61, 0x6e,
0x69, 0x66, 0x65, 0x73, 0x74, 0x73, 0x22, 0x28, 0x0a, 0x12, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52,
0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
0x22, 0x41, 0x0a, 0x13, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x09, 0x6d, 0x61, 0x6e, 0x69, 0x66,
0x65, 0x73, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x70, 0x62, 0x2e,
0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x52, 0x09, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65,
0x73, 0x74, 0x73, 0x32, 0xd1, 0x01, 0x0a, 0x0c, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x12, 0x3a, 0x0a, 0x09, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73,
0x74, 0x12, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x61,
0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
0x12, 0x43, 0x0a, 0x0c, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74,
0x12, 0x17, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x73, 0x70, 0x65,
0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x49,
0x6d, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x0b, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65,
0x6d, 0x6f, 0x76, 0x65, 0x12, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52,
0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70,
0x62, 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x1e, 0x5a, 0x1c, 0x67, 0x69, 0x74, 0x68, 0x75,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x61, 0x7a, 0x79, 0x2d, 0x6d, 0x61, 0x78, 0x2f,
0x64, 0x69, 0x75, 0x6e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_image_proto_rawDescOnce sync.Once
file_image_proto_rawDescData = file_image_proto_rawDesc
)
func file_image_proto_rawDescGZIP() []byte {
file_image_proto_rawDescOnce.Do(func() {
file_image_proto_rawDescData = protoimpl.X.CompressGZIP(file_image_proto_rawDescData)
})
return file_image_proto_rawDescData
}
var file_image_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
var file_image_proto_goTypes = []interface{}{
(*Manifest)(nil), // 0: pb.Manifest
(*ImageListRequest)(nil), // 1: pb.ImageListRequest
(*ImageListResponse)(nil), // 2: pb.ImageListResponse
(*ImageInspectRequest)(nil), // 3: pb.ImageInspectRequest
(*ImageInspectResponse)(nil), // 4: pb.ImageInspectResponse
(*ImageRemoveRequest)(nil), // 5: pb.ImageRemoveRequest
(*ImageRemoveResponse)(nil), // 6: pb.ImageRemoveResponse
nil, // 7: pb.Manifest.LabelsEntry
(*ImageListResponse_Image)(nil), // 8: pb.ImageListResponse.Image
(*ImageInspectResponse_Image)(nil), // 9: pb.ImageInspectResponse.Image
(*timestamppb.Timestamp)(nil), // 10: google.protobuf.Timestamp
}
var file_image_proto_depIdxs = []int32{
10, // 0: pb.Manifest.created:type_name -> google.protobuf.Timestamp
7, // 1: pb.Manifest.labels:type_name -> pb.Manifest.LabelsEntry
8, // 2: pb.ImageListResponse.images:type_name -> pb.ImageListResponse.Image
9, // 3: pb.ImageInspectResponse.image:type_name -> pb.ImageInspectResponse.Image
0, // 4: pb.ImageRemoveResponse.manifests:type_name -> pb.Manifest
0, // 5: pb.ImageListResponse.Image.latest:type_name -> pb.Manifest
0, // 6: pb.ImageInspectResponse.Image.manifests:type_name -> pb.Manifest
1, // 7: pb.ImageService.ImageList:input_type -> pb.ImageListRequest
3, // 8: pb.ImageService.ImageInspect:input_type -> pb.ImageInspectRequest
5, // 9: pb.ImageService.ImageRemove:input_type -> pb.ImageRemoveRequest
2, // 10: pb.ImageService.ImageList:output_type -> pb.ImageListResponse
4, // 11: pb.ImageService.ImageInspect:output_type -> pb.ImageInspectResponse
6, // 12: pb.ImageService.ImageRemove:output_type -> pb.ImageRemoveResponse
10, // [10:13] is the sub-list for method output_type
7, // [7:10] is the sub-list for method input_type
7, // [7:7] is the sub-list for extension type_name
7, // [7:7] is the sub-list for extension extendee
0, // [0:7] is the sub-list for field type_name
}
func init() { file_image_proto_init() }
func file_image_proto_init() {
if File_image_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_image_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Manifest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_image_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ImageListRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_image_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ImageListResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_image_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ImageInspectRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_image_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ImageInspectResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_image_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ImageRemoveRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_image_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ImageRemoveResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_image_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ImageListResponse_Image); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_image_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ImageInspectResponse_Image); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_image_proto_rawDesc,
NumEnums: 0,
NumMessages: 10,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_image_proto_goTypes,
DependencyIndexes: file_image_proto_depIdxs,
MessageInfos: file_image_proto_msgTypes,
}.Build()
File_image_proto = out.File
file_image_proto_rawDesc = nil
file_image_proto_goTypes = nil
file_image_proto_depIdxs = nil
}

53
pb/image.proto Normal file
View File

@@ -0,0 +1,53 @@
syntax = "proto3";
option go_package = "github.com/crazy-max/diun/pb";
package pb;
import "google/protobuf/timestamp.proto";
message Manifest {
string tag = 1;
string mime_type = 2;
string digest = 3;
google.protobuf.Timestamp created = 4;
map<string, string> labels = 5;
string platform = 6;
int64 size = 7;
}
message ImageListRequest {}
message ImageListResponse {
message Image {
string name = 1;
int64 manifestsCount = 2;
Manifest latest = 3;
}
repeated Image images = 1;
}
message ImageInspectRequest {
string name = 1;
}
message ImageInspectResponse {
message Image {
string name = 1;
repeated Manifest manifests = 2;
}
Image image = 1;
}
message ImageRemoveRequest {
string name = 1;
}
message ImageRemoveResponse {
repeated Manifest manifests = 1;
}
service ImageService {
rpc ImageList(ImageListRequest) returns (ImageListResponse) {}
rpc ImageInspect(ImageInspectRequest) returns (ImageInspectResponse) {}
rpc ImageRemove(ImageRemoveRequest) returns (ImageRemoveResponse) {}
}

173
pb/image_grpc.pb.go Normal file
View File

@@ -0,0 +1,173 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package pb
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// ImageServiceClient is the client API for ImageService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type ImageServiceClient interface {
ImageList(ctx context.Context, in *ImageListRequest, opts ...grpc.CallOption) (*ImageListResponse, error)
ImageInspect(ctx context.Context, in *ImageInspectRequest, opts ...grpc.CallOption) (*ImageInspectResponse, error)
ImageRemove(ctx context.Context, in *ImageRemoveRequest, opts ...grpc.CallOption) (*ImageRemoveResponse, error)
}
type imageServiceClient struct {
cc grpc.ClientConnInterface
}
func NewImageServiceClient(cc grpc.ClientConnInterface) ImageServiceClient {
return &imageServiceClient{cc}
}
func (c *imageServiceClient) ImageList(ctx context.Context, in *ImageListRequest, opts ...grpc.CallOption) (*ImageListResponse, error) {
out := new(ImageListResponse)
err := c.cc.Invoke(ctx, "/pb.ImageService/ImageList", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *imageServiceClient) ImageInspect(ctx context.Context, in *ImageInspectRequest, opts ...grpc.CallOption) (*ImageInspectResponse, error) {
out := new(ImageInspectResponse)
err := c.cc.Invoke(ctx, "/pb.ImageService/ImageInspect", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *imageServiceClient) ImageRemove(ctx context.Context, in *ImageRemoveRequest, opts ...grpc.CallOption) (*ImageRemoveResponse, error) {
out := new(ImageRemoveResponse)
err := c.cc.Invoke(ctx, "/pb.ImageService/ImageRemove", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ImageServiceServer is the server API for ImageService service.
// All implementations must embed UnimplementedImageServiceServer
// for forward compatibility
type ImageServiceServer interface {
ImageList(context.Context, *ImageListRequest) (*ImageListResponse, error)
ImageInspect(context.Context, *ImageInspectRequest) (*ImageInspectResponse, error)
ImageRemove(context.Context, *ImageRemoveRequest) (*ImageRemoveResponse, error)
mustEmbedUnimplementedImageServiceServer()
}
// UnimplementedImageServiceServer must be embedded to have forward compatible implementations.
type UnimplementedImageServiceServer struct {
}
func (UnimplementedImageServiceServer) ImageList(context.Context, *ImageListRequest) (*ImageListResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ImageList not implemented")
}
func (UnimplementedImageServiceServer) ImageInspect(context.Context, *ImageInspectRequest) (*ImageInspectResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ImageInspect not implemented")
}
func (UnimplementedImageServiceServer) ImageRemove(context.Context, *ImageRemoveRequest) (*ImageRemoveResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ImageRemove not implemented")
}
func (UnimplementedImageServiceServer) mustEmbedUnimplementedImageServiceServer() {}
// UnsafeImageServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ImageServiceServer will
// result in compilation errors.
type UnsafeImageServiceServer interface {
mustEmbedUnimplementedImageServiceServer()
}
func RegisterImageServiceServer(s grpc.ServiceRegistrar, srv ImageServiceServer) {
s.RegisterService(&ImageService_ServiceDesc, srv)
}
func _ImageService_ImageList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ImageListRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ImageServiceServer).ImageList(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pb.ImageService/ImageList",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ImageServiceServer).ImageList(ctx, req.(*ImageListRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ImageService_ImageInspect_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ImageInspectRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ImageServiceServer).ImageInspect(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pb.ImageService/ImageInspect",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ImageServiceServer).ImageInspect(ctx, req.(*ImageInspectRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ImageService_ImageRemove_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ImageRemoveRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ImageServiceServer).ImageRemove(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pb.ImageService/ImageRemove",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ImageServiceServer).ImageRemove(ctx, req.(*ImageRemoveRequest))
}
return interceptor(ctx, in, info, handler)
}
// ImageService_ServiceDesc is the grpc.ServiceDesc for ImageService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var ImageService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "pb.ImageService",
HandlerType: (*ImageServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "ImageList",
Handler: _ImageService_ImageList_Handler,
},
{
MethodName: "ImageInspect",
Handler: _ImageService_ImageInspect_Handler,
},
{
MethodName: "ImageRemove",
Handler: _ImageService_ImageRemove_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "image.proto",
}

202
pb/notif.pb.go Normal file
View File

@@ -0,0 +1,202 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.17.0
// source: notif.proto
package pb
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type NotifTestRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *NotifTestRequest) Reset() {
*x = NotifTestRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_notif_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *NotifTestRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NotifTestRequest) ProtoMessage() {}
func (x *NotifTestRequest) ProtoReflect() protoreflect.Message {
mi := &file_notif_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NotifTestRequest.ProtoReflect.Descriptor instead.
func (*NotifTestRequest) Descriptor() ([]byte, []int) {
return file_notif_proto_rawDescGZIP(), []int{0}
}
type NotifTestResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
}
func (x *NotifTestResponse) Reset() {
*x = NotifTestResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_notif_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *NotifTestResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*NotifTestResponse) ProtoMessage() {}
func (x *NotifTestResponse) ProtoReflect() protoreflect.Message {
mi := &file_notif_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use NotifTestResponse.ProtoReflect.Descriptor instead.
func (*NotifTestResponse) Descriptor() ([]byte, []int) {
return file_notif_proto_rawDescGZIP(), []int{1}
}
func (x *NotifTestResponse) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
var File_notif_proto protoreflect.FileDescriptor
var file_notif_proto_rawDesc = []byte{
0x0a, 0x0b, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70,
0x62, 0x22, 0x12, 0x0a, 0x10, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x2d, 0x0a, 0x11, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x54, 0x65,
0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x32, 0x4a, 0x0a, 0x0c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x53, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x12, 0x3a, 0x0a, 0x09, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x54, 0x65, 0x73,
0x74, 0x12, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x54, 0x65, 0x73, 0x74,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x6f, 0x74,
0x69, 0x66, 0x54, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
0x42, 0x1e, 0x5a, 0x1c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63,
0x72, 0x61, 0x7a, 0x79, 0x2d, 0x6d, 0x61, 0x78, 0x2f, 0x64, 0x69, 0x75, 0x6e, 0x2f, 0x70, 0x62,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_notif_proto_rawDescOnce sync.Once
file_notif_proto_rawDescData = file_notif_proto_rawDesc
)
func file_notif_proto_rawDescGZIP() []byte {
file_notif_proto_rawDescOnce.Do(func() {
file_notif_proto_rawDescData = protoimpl.X.CompressGZIP(file_notif_proto_rawDescData)
})
return file_notif_proto_rawDescData
}
var file_notif_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_notif_proto_goTypes = []interface{}{
(*NotifTestRequest)(nil), // 0: pb.NotifTestRequest
(*NotifTestResponse)(nil), // 1: pb.NotifTestResponse
}
var file_notif_proto_depIdxs = []int32{
0, // 0: pb.NotifService.NotifTest:input_type -> pb.NotifTestRequest
1, // 1: pb.NotifService.NotifTest:output_type -> pb.NotifTestResponse
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_notif_proto_init() }
func file_notif_proto_init() {
if File_notif_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_notif_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NotifTestRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_notif_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*NotifTestResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_notif_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_notif_proto_goTypes,
DependencyIndexes: file_notif_proto_depIdxs,
MessageInfos: file_notif_proto_msgTypes,
}.Build()
File_notif_proto = out.File
file_notif_proto_rawDesc = nil
file_notif_proto_goTypes = nil
file_notif_proto_depIdxs = nil
}

14
pb/notif.proto Normal file
View File

@@ -0,0 +1,14 @@
syntax = "proto3";
option go_package = "github.com/crazy-max/diun/pb";
package pb;
message NotifTestRequest {}
message NotifTestResponse {
string message = 1;
}
service NotifService {
rpc NotifTest(NotifTestRequest) returns (NotifTestResponse) {}
}

101
pb/notif_grpc.pb.go Normal file
View File

@@ -0,0 +1,101 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package pb
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// NotifServiceClient is the client API for NotifService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type NotifServiceClient interface {
NotifTest(ctx context.Context, in *NotifTestRequest, opts ...grpc.CallOption) (*NotifTestResponse, error)
}
type notifServiceClient struct {
cc grpc.ClientConnInterface
}
func NewNotifServiceClient(cc grpc.ClientConnInterface) NotifServiceClient {
return &notifServiceClient{cc}
}
func (c *notifServiceClient) NotifTest(ctx context.Context, in *NotifTestRequest, opts ...grpc.CallOption) (*NotifTestResponse, error) {
out := new(NotifTestResponse)
err := c.cc.Invoke(ctx, "/pb.NotifService/NotifTest", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// NotifServiceServer is the server API for NotifService service.
// All implementations must embed UnimplementedNotifServiceServer
// for forward compatibility
type NotifServiceServer interface {
NotifTest(context.Context, *NotifTestRequest) (*NotifTestResponse, error)
mustEmbedUnimplementedNotifServiceServer()
}
// UnimplementedNotifServiceServer must be embedded to have forward compatible implementations.
type UnimplementedNotifServiceServer struct {
}
func (UnimplementedNotifServiceServer) NotifTest(context.Context, *NotifTestRequest) (*NotifTestResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method NotifTest not implemented")
}
func (UnimplementedNotifServiceServer) mustEmbedUnimplementedNotifServiceServer() {}
// UnsafeNotifServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to NotifServiceServer will
// result in compilation errors.
type UnsafeNotifServiceServer interface {
mustEmbedUnimplementedNotifServiceServer()
}
func RegisterNotifServiceServer(s grpc.ServiceRegistrar, srv NotifServiceServer) {
s.RegisterService(&NotifService_ServiceDesc, srv)
}
func _NotifService_NotifTest_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(NotifTestRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(NotifServiceServer).NotifTest(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/pb.NotifService/NotifTest",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(NotifServiceServer).NotifTest(ctx, req.(*NotifTestRequest))
}
return interceptor(ctx, in, info, handler)
}
// NotifService_ServiceDesc is the grpc.ServiceDesc for NotifService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var NotifService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "pb.NotifService",
HandlerType: (*NotifServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "NotifTest",
Handler: _NotifService_NotifTest_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "notif.proto",
}

8
tools.go Normal file
View File

@@ -0,0 +1,8 @@
// +build tools
package tools
import (
_ "google.golang.org/grpc/cmd/protoc-gen-go-grpc"
_ "google.golang.org/protobuf/cmd/protoc-gen-go"
)