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
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:
runs-on: ubuntu-latest
steps:
@@ -49,7 +64,9 @@ jobs:
build:
runs-on: ubuntu-latest
needs: [ test ]
needs:
- validate
- test
steps:
-
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" \
--hooks="go mod tidy" \
--hooks="go mod download" \
--main="./cmd/main.go" \
--main="./cmd" \
--ldflags="-s -w -X 'main.version={{.Version}}'" \
--files="CHANGELOG.md" \
--files="LICENSE" \
@@ -44,3 +44,4 @@ ENV PROFILER_PATH="/profiler" \
VOLUME [ "/data" ]
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 (
"fmt"
"os"
"os/signal"
"path"
"runtime"
"strings"
"syscall"
_ "time/tzdata"
"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/pkg/profile"
"github.com/rs/zerolog/log"
)
var (
diun *app.Diun
cli model.Cli
version = "dev"
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",
cli struct {
Version kong.VersionFlag
Serve ServeCmd `kong:"cmd,help='Starts Diun server.'"`
Image ImageCmd `kong:"cmd,help='Manage image manifests.'"`
Notif NotifCmd `kong:"cmd,help='Manage notifications.'"`
}
)
type Context struct {
Meta model.Meta
}
func main() {
var err error
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))
if meta.Hostname, err = os.Hostname(); err != nil {
log.Fatal().Err(err).Msg("Cannot resolve hostname")
}
// Parse command line
_ = kong.Parse(&cli,
ctx := kong.Parse(&cli,
kong.Name(meta.ID),
kong.Description(fmt.Sprintf("%s. More info: %s", meta.Desc, meta.URL)),
kong.UsageOnError(),
@@ -56,69 +56,5 @@ func main() {
Summary: true,
}))
// Init
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)
}
ctx.FatalIfErrorf(ctx.Run(&Context{Meta: meta}))
}

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))
variable "GITHUB_REF" {
default = ""
@@ -30,7 +41,7 @@ group "default" {
}
group "validate" {
targets = ["lint", "vendor-validate"]
targets = ["lint", "vendor-validate", "gen-validate"]
}
target "lint" {
@@ -52,6 +63,19 @@ target "vendor-update" {
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" {
inherits = ["go-version"]
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/`
* `.` _(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"
```yaml

View File

@@ -20,13 +20,11 @@ regopts:
passwordFile: /run/secrets/password
```
`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 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.
* `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
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

View File

@@ -60,7 +60,7 @@ Send notification at the very first analysis of an image. (default `false`)
### `compareDigest`
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`)
!!! example "Config file"
@@ -74,7 +74,7 @@ on image pull. (default `true`)
### `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/).
!!! tip

View File

@@ -14,16 +14,16 @@ watch:
## Test notifications
Through the [command line](usage/cli.md) with:
Through the [command line](usage/command-line.md#notif-test) with:
```shell
diun --config ./diun.yml --test-notif
diun notif test
```
Or within a container:
```shell
docker-compose exec diun diun --test-notif
docker-compose exec diun diun notif test
```
## 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
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
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
```
After getting the binary, it can be tested with [`./diun --help`](../usage/cli.md) command and moved to a permanent
location.
After getting the binary, it can be tested with [`./diun --help`](../usage/command-line.md#global-options) command
and moved to a permanent location.
## 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.
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
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
go 1.15
go 1.16
require (
github.com/alecthomas/kong v0.2.16
@@ -11,6 +11,7 @@ require (
github.com/crazy-max/gonfig v0.4.0
github.com/docker/docker v20.10.6+incompatible
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/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df
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/hako/durafmt v0.0.0-20190612201238-650ed9f29a84
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/matrix-org/gomatrix v0.0.0-20200501121722-e5578b12c752
github.com/microcosm-cc/bluemonday v1.0.9
@@ -35,7 +37,11 @@ require (
github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71
github.com/stretchr/testify v1.7.0
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
github.com/tidwall/pretty v1.1.0
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/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
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/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
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-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/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
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/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.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.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/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
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.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
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/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
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.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
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.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.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
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.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.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.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.1.2 h1:YjFNKqxzWUVZND8d4ItF9wuYlE75WQfECE7yKX/Nu3o=
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/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/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/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
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-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.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/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
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.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
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.6.0 h1:hUDfIISABYI59DyeB3OTay/HxSRwTQ8rB/H83k6r5dM=
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.4.2 h1:Dib7un+rYJFUi8vN0Bk6EHheKy6fv6ZzFURHw75g6m8=
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-20200424151742-cb6215831a94 h1:ig99OeTyDwQWhPe2iw9lwfQVF1KB3Q4fpP3X7/2VBG8=
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/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-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-20180830151530-49385e6e1522/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.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
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.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-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
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.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.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.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/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
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/db"
"github.com/crazy-max/diun/v4/internal/grpc"
"github.com/crazy-max/diun/v4/internal/logging"
"github.com/crazy-max/diun/v4/internal/model"
"github.com/crazy-max/diun/v4/internal/notif"
@@ -16,7 +17,6 @@ import (
filePrd "github.com/crazy-max/diun/v4/internal/provider/file"
kubernetesPrd "github.com/crazy-max/diun/v4/internal/provider/kubernetes"
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/hako/durafmt"
"github.com/panjf2000/ants/v2"
@@ -27,12 +27,15 @@ import (
// Diun represents an active diun object
type Diun struct {
meta model.Meta
cfg *config.Config
meta model.Meta
cfg *config.Config
db *db.Client
grpc *grpc.Client
hc *gohealthchecks.Client
notif *notif.Client
cron *cron.Cron
db *db.Client
hc *gohealthchecks.Client
notif *notif.Client
jobID cron.EntryID
locker uint32
pool *ants.PoolWithFunc
@@ -40,7 +43,7 @@ type Diun struct {
}
// 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
diun := &Diun{
@@ -56,11 +59,14 @@ func New(meta model.Meta, cli model.Cli, cfg *config.Config) (*Diun, error) {
return nil, err
}
if !cli.TestNotif {
diun.db, err = db.New(*cfg.Db)
if err != nil {
return nil, err
}
diun.db, err = db.New(*cfg.Db)
if err != nil {
return nil, err
}
diun.grpc, err = grpc.New(grpcAuthority, diun.db, diun.notif)
if err != nil {
return nil, err
}
if cfg.Watch.Healthchecks != nil {
@@ -89,6 +95,13 @@ func (di *Diun) Start() error {
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
di.Run()
@@ -157,7 +170,7 @@ func (di *Diun) Run() {
di.createJob(job)
}
// Dokcerfile provider
// Dockerfile provider
for _, job := range dockerfilePrd.New(di.cfg.Providers.Dockerfile).ListJob() {
di.createJob(job)
}
@@ -178,51 +191,8 @@ func (di *Diun) Close() {
if di.cron != nil {
di.cron.Stop()
}
di.grpc.Stop()
if err := di.db.Close(); err != nil {
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
func Load(cli model.Cli) (*Config, error) {
func Load(config string) (*Config, error) {
cfg := Config{
Db: (&model.Db{}).GetDefaults(),
Watch: (&model.Watch{}).GetDefaults(),
}
fileLoader := gonfig.NewFileLoader(gonfig.FileLoaderConfig{
Filename: cli.Cfgfile,
Filename: config,
Finder: gonfig.Finder{
BasePaths: []string{"/etc/diun/diun", "$XDG_CONFIG_HOME/diun", "$HOME/.config/diun", "./diun"},
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()))
}
if err := cfg.validate(cli); err != nil {
if err := cfg.validate(); err != nil {
return nil, err
}
return &cfg, nil
}
func (cfg *Config) validate(cli model.Cli) error {
func (cfg *Config) validate() error {
if len(cfg.Db.Path) > 0 {
if err := os.MkdirAll(path.Dir(cfg.Db.Path), os.ModePerm); err != nil {
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")
}
if cfg.Notif == nil && cli.TestNotif {
return errors.New("At least one notifier is required")
}
if cfg.Providers == nil && !cli.TestNotif {
if cfg.Providers == nil {
return errors.New("At least one provider is required")
}

View File

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

View File

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

View File

@@ -3,6 +3,7 @@ package db
import (
"bytes"
"encoding/json"
"fmt"
"github.com/crazy-max/diun/v4/pkg/registry"
bolt "go.etcd.io/bbolt"
@@ -25,6 +26,25 @@ func (c *Client) First(image registry.Image) (bool, error) {
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
func (c *Client) GetManifest(image registry.Image) (registry.Manifest, error) {
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
func (c *Client) PutManifest(image registry.Image, manifest registry.Manifest) error {
entryBytes, _ := json.Marshal(manifest)
err := c.Update(func(tx *bolt.Tx) error {
return c.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(bucketManifest))
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
func (c *Client) WriteMetadata(metadata Metadata) error {
entryBytes, _ := json.Marshal(metadata)
err := c.Update(func(tx *bolt.Tx) error {
return c.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(bucketMetadata))
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 err
}
return nil
return tx.Commit()
}

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"
"time"
"github.com/crazy-max/diun/v4/internal/model"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/sirupsen/logrus"
)
type Options struct {
LogLevel string
LogJSON bool
LogCaller bool
LogNoColor bool
}
// Configure configures logger
func Configure(cli *model.Cli) {
func Configure(opts Options) {
var err error
var w io.Writer
// Adds support for NO_COLOR. More info https://no-color.org/
_, noColor := os.LookupEnv("NO_COLOR")
if !cli.LogJSON {
if !opts.LogJSON {
w = zerolog.ConsoleWriter{
Out: os.Stdout,
NoColor: noColor || cli.LogNoColor,
NoColor: noColor || opts.LogNoColor,
TimeFormat: time.RFC1123,
}
} else {
@@ -31,20 +37,20 @@ func Configure(cli *model.Cli) {
}
ctx := zerolog.New(w).With().Timestamp()
if cli.LogCaller {
if opts.LogCaller {
ctx = ctx.Caller()
}
log.Logger = ctx.Logger()
logLevel, err := zerolog.ParseLevel(cli.LogLevel)
logLevel, err := zerolog.ParseLevel(opts.LogLevel)
if err != nil {
log.Fatal().Err(err).Msgf("Unknown log level")
} else {
zerolog.SetGlobalLevel(logLevel)
}
logrusLevel, err := logrus.ParseLevel(cli.LogLevel)
logrusLevel, err := logrus.ParseLevel(opts.LogLevel)
if err != nil {
log.Fatal().Err(err).Msgf("Unknown log level")
} 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
- Linux service: install/linux-service.md
- Usage:
- Command line: usage/cli.md
- Command line: usage/command-line.md
- Basic example: usage/basic-example.md
- Configuration:
- Overview: config/index.md
@@ -125,6 +125,7 @@ nav:
- FAQ: faq.md
- Changelog: changelog.md
- Migration:
- Diun v4.0 to v4.17: migration/v4.0-to-v4.17.md
- Diun v3 to v4: migration/v3-to-v4.md
- Diun v2 to v3: migration/v2-to-v3.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"
)