Compare commits

..

26 Commits

Author SHA1 Message Date
IamTheFij 301563c302 Update pipeline notify
continuous-integration/drone/push Build was killed Details
2020-08-19 14:09:37 -07:00
IamTheFij 4cdd1eab9e Update pipeline notify
continuous-integration/drone/push Build was killed Details
2020-08-19 14:08:01 -07:00
IamTheFij eac49e36b0 Remove itest
continuous-integration/drone/push Build is failing Details
2020-08-19 13:59:27 -07:00
IamTheFij 3de07349ed Make sure version is set when building final binaries 2020-08-19 13:57:49 -07:00
IamTheFij c742a324ed Add bash to drone itest
continuous-integration/drone/push Build is failing Details
2020-08-19 13:56:20 -07:00
IamTheFij a5406be70b More itest debugging
continuous-integration/drone/push Build is failing Details
2020-08-19 13:52:36 -07:00
IamTheFij bb0db6a9d6 Debug itest
continuous-integration/drone/push Build is failing Details
2020-08-19 13:51:36 -07:00
IamTheFij 0e09d2ca2c Fix hadolint install
continuous-integration/drone/push Build is failing Details
2020-08-19 13:47:54 -07:00
IamTheFij c9d19f9c01 Add git to itest
continuous-integration/drone/push Build is failing Details
Don't actually know why this is needed
2020-08-19 13:44:10 -07:00
IamTheFij 7e9f2e38ca Try to add hadolint back 2020-08-19 13:42:55 -07:00
IamTheFij 996d31b9eb Change to compose base
continuous-integration/drone/push Build is failing Details
2020-08-19 13:34:52 -07:00
IamTheFij e3431971a0 Try to add itest to drone build
continuous-integration/drone/push Build is failing Details
2020-08-19 13:29:53 -07:00
IamTheFij 4bf79f769e Skip hadolint in drone check
continuous-integration/drone/push Build is failing Details
2020-08-19 13:25:45 -07:00
IamTheFij 088bf2ab5e Switch to different python base image for checks
continuous-integration/drone/push Build is failing Details
2020-08-19 13:21:12 -07:00
IamTheFij 4ef3f0b431 Remove build step as build is part of test
continuous-integration/drone/push Build is failing Details
2020-08-19 13:16:50 -07:00
IamTheFij f4c7801d84 Install pre-commit for checks
continuous-integration/drone/push Build is failing Details
2020-08-19 13:15:45 -07:00
IamTheFij 0b8454bb80 Add drone email notifications
continuous-integration/drone/push Build is failing Details
2020-08-19 13:14:48 -07:00
IamTheFij 61171cc9eb Add tests to drone
continuous-integration/drone/push Build is failing Details
2020-08-19 13:12:17 -07:00
IamTheFij a1ba2060bb Add integration test 2020-08-19 13:04:37 -07:00
IamTheFij a572bd6635 Fix multi-stage build with slog 2020-08-19 12:51:30 -07:00
IamTheFij 1fc9672971 Update tests to 75%+ coverage
continuous-integration/drone/push Build is failing Details
2020-08-19 10:19:43 -07:00
IamTheFij 63532b39f8 WIP Yea tests!
continuous-integration/drone/push Build is failing Details
2020-08-18 22:07:41 -07:00
IamTheFij 73b7a12eb7 Update slog interfaces
continuous-integration/drone/push Build is failing Details
2020-08-17 15:34:47 -07:00
IamTheFij 32d681703c Add script to add documentation to readme 2020-08-16 16:13:25 -07:00
IamTheFij 4cb0b027cd Move logger module to a subpackage
This will allow me to use my logging helpers from another project
2020-08-16 15:03:09 -07:00
IamTheFij 3ee32b632a Add the ability to create execute jobs on long running containers 2020-08-16 14:46:35 -07:00
12 changed files with 305 additions and 236 deletions

View File

@ -9,9 +9,12 @@ steps:
- make test
- name: check
image: iamthefij/drone-pre-commit:personal
environment:
SKIP: docker-compose-check
image: python:3
commands:
- pip install docker-compose pre-commit
- wget -L -O /usr/bin/hadolint https://github.com/hadolint/hadolint/releases/download/v1.18.0/hadolint-Linux-x86_64
- chmod +x /usr/bin/hadolint
- make check
# - name: itest
# image: docker/compose:alpine-1.26.2

View File

@ -1,23 +1,21 @@
---
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.4.0
rev: v2.4.0
hooks:
- id: check-added-large-files
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-merge-conflict
- repo: git://github.com/dnephin/pre-commit-golang
rev: v0.4.0
rev: v0.3.5
hooks:
- id: go-fmt
- id: go-imports
- id: golangci-lint
# - id: gometalinter
# - id: golangci-lint
- repo: https://github.com/IamTheFij/docker-pre-commit
rev: v2.0.0
hooks:
- id: docker-compose-check
- repo: https://github.com/hadolint/hadolint
rev: v2.4.0
hooks:
- id: hadolint
- id: hadolint-system

View File

@ -11,6 +11,7 @@ COPY ./go.mod ./go.sum /app/
RUN go mod download
COPY ./main.go /app/
COPY ./slog /app/slog
ARG ARCH=amd64
ARG VERSION=dev

View File

@ -1,8 +1,7 @@
OUTPUT ?= dockron
DOCKER_TAG ?= $(OUTPUT)-dev-$(USER)
DOCKER_TAG ?= dockron-dev-${USER}
GIT_TAG_NAME := $(shell git tag -l --contains HEAD)
GIT_SHA := $(shell git rev-parse HEAD)
VERSION ?= $(if $(GIT_TAG_NAME),$(GIT_TAG_NAME),$(GIT_SHA))
VERSION := $(if $(GIT_TAG_NAME),$(GIT_TAG_NAME),$(GIT_SHA))
GOFILES = *.go go.mod go.sum
@ -43,45 +42,45 @@ check:
pre-commit run --all-files
# Output target
$(OUTPUT): $(GOFILES)
dockron: $(GOFILES)
@echo Version: $(VERSION)
go build -ldflags '-X "main.version=$(VERSION)"' -o $(OUTPUT)
go build -ldflags '-X "main.version=${VERSION}"' -o dockron
# Alias for building
.PHONY: build
build: $(OUTPUT)
build: dockron
$(OUTPUT)-darwin-amd64: $(GOFILES)
dockron-darwin-amd64: $(GOFILES)
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 \
go build -ldflags '-X "main.version=$(VERSION)"' -a -installsuffix nocgo \
-o $(OUTPUT)-darwin-amd64
go build -ldflags '-X "main.version=${VERSION}"' -a -installsuffix nocgo \
-o dockron-darwin-amd64
$(OUTPUT)-linux-amd64: $(GOFILES)
dockron-linux-amd64: $(GOFILES)
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 \
go build -ldflags '-X "main.version=$(VERSION)"' -a -installsuffix nocgo \
-o $(OUTPUT)-linux-amd64
go build -ldflags '-X "main.version=${VERSION}"' -a -installsuffix nocgo \
-o dockron-linux-amd64
$(OUTPUT)-linux-arm: $(GOFILES)
dockron-linux-arm: $(GOFILES)
GOOS=linux GOARCH=arm CGO_ENABLED=0 \
go build -ldflags '-X "main.version=$(VERSION)"' -a -installsuffix nocgo \
-o $(OUTPUT)-linux-arm
go build -ldflags '-X "main.version=${VERSION}"' -a -installsuffix nocgo \
-o dockron-linux-arm
$(OUTPUT)-linux-arm64: $(GOFILES)
dockron-linux-arm64: $(GOFILES)
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 \
go build -ldflags '-X "main.version=$(VERSION)"' -a -installsuffix nocgo \
-o $(OUTPUT)-linux-arm64
go build -ldflags '-X "main.version=${VERSION}"' -a -installsuffix nocgo \
-o dockron-linux-arm64
.PHONY: build-linux-static
build-linux-static: $(OUTPUT)-linux-amd64 $(OUTPUT)-linux-arm $(OUTPUT)-linux-arm64
build-linux-static: dockron-linux-amd64 dockron-linux-arm dockron-linux-arm64
.PHONY: build-all-static
build-all-static: $(OUTPUT)-darwin-amd64 build-linux-static
build-all-static: dockron-darwin-amd64 build-linux-static
# Cleans all build artifacts
.PHONY: clean
clean:
rm -f $(OUTPUT)
rm -f $(OUTPUT)-linux-*
rm -f dockron
rm -f dockron-linux-*
# Cleans vendor directory
.PHONY: clean-vendor
@ -89,17 +88,17 @@ clean-vendor:
rm -fr ./vendor
.PHONY: docker-build
docker-build: $(OUTPUT)-linux-amd64
docker build . -t $(DOCKER_TAG)-linux-amd64
docker-build: dockron-linux-amd64
docker build . -t ${DOCKER_TAG}-linux-amd64
# Cross build for arm architechtures
.PHONY: docker-build-arm
docker-build-arm: $(OUTPUT)-linux-arm
docker build --build-arg REPO=arm32v7 --build-arg ARCH=arm . -t $(DOCKER_TAG)-linux-arm
docker-build-arm: dockron-linux-arm
docker build --build-arg REPO=arm32v7 --build-arg ARCH=arm . -t ${DOCKER_TAG}-linux-arm
.PHONY: docker-build-arm
docker-build-arm64: $(OUTPUT)-linux-arm64
docker build --build-arg REPO=arm64v8 --build-arg ARCH=arm64 . -t $(DOCKER_TAG)-linux-arm64
docker-build-arm64: dockron-linux-arm64
docker build --build-arg REPO=arm64v8 --build-arg ARCH=arm64 . -t ${DOCKER_TAG}-linux-arm64
.PHONY: docker-run
docker-run: docker-build
@ -108,30 +107,30 @@ docker-run: docker-build
# Cross run on host architechture
.PHONY: docker-run-arm
docker-run-arm: docker-build-arm
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock --name $(DOCKER_TAG)-run $(DOCKER_TAG)-linux-arm
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock --name $(DOCKER_TAG)-run ${DOCKER_TAG}-linux-arm
.PHONY: docker-run-arm64
docker-run-arm64: docker-build-arm64
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock --name $(DOCKER_TAG)-run $(DOCKER_TAG)-linux-arm64
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock --name $(DOCKER_TAG)-run ${DOCKER_TAG}-linux-arm64
# Multi stage builds
.PHONY: docker-staged-build
docker-staged-build:
docker build --build-arg VERSION=$(VERSION) \
-t $(DOCKER_TAG)-linux-amd64 \
docker build --build-arg VERSION=${VERSION} \
-t ${DOCKER_TAG}-linux-amd64 \
-f Dockerfile.multi-stage .
# Cross build for arm architechtures
.PHONY: docker-staged-build-arm
docker-staged-build-arm:
docker build --build-arg VERSION=$(VERSION) \
--build-arg REPO=arm32v7 --build-arg ARCH=arm -t $(DOCKER_TAG)-linux-arm \
docker build --build-arg VERSION=${VERSION} \
--build-arg REPO=arm32v7 --build-arg ARCH=arm -t ${DOCKER_TAG}-linux-arm \
-f Dockerfile.multi-stage .
.PHONY: docker-staged-build-arm
docker-staged-build-arm64:
docker build --build-arg VERSION=$(VERSION) \
--build-arg REPO=arm64v8 --build-arg ARCH=arm64 -t $(DOCKER_TAG)-linux-arm64 \
docker build --build-arg VERSION=${VERSION} \
--build-arg REPO=arm64v8 --build-arg ARCH=arm64 -t ${DOCKER_TAG}-linux-arm64 \
-f Dockerfile.multi-stage .
.PHONY: docker-example

View File

@ -32,16 +32,6 @@ Create your container and add a label in the form `'dockron.schedule=* * * * *'`
Dockron will now start that container peridically on the schedule.
If you have a long running container that you'd like to schedule an exec command inside of, you can do so with labels as well. Add your job in the form `dockron.<job>.schedule=* * * * *` and `dockeron.<job>.command=echo hello`. Both labels are required to create an exec job.
Eg.
labels:
- "dockron.dates.schedule=* * * * *"
- "dockron.dates.command=date"
_Note: Exec jobs will not log their output anywhere. Not to the host container or to Dockron. It's up to you to deal with this for now. There is also currently no way to health check these._
### Cron Expression Formatting
For more information on the cron expression parsing, see the docs for [robfig/cron](https://godoc.org/github.com/robfig/cron).
@ -65,7 +55,3 @@ Either use a separate tool in conjunction with Dockron, or use a more robust sch
If you have go on your machine, you can simply use `make build` or `make run` to build and test Dockron. If you don't have go but you do have Docker, you can still build docker images using the provide multi-stage Dockerfile! You can kick that off with `make docker-staged-build`
There is also an example `docker-compose.yml` that will use the multi-stage build to ensure an easy sample. This can be run with `make docker-example`.
## Tests
There are now some basic tests as well as linting and integration tests. You can run all of these by executing `make all`.

31
go.mod
View File

@ -1,27 +1,26 @@
module github.com/iamthefij/dockron
go 1.15
go 1.12
require (
git.iamthefij.com/iamthefij/slog v1.3.0
github.com/Microsoft/go-winio v0.5.0 // indirect
github.com/containerd/containerd v1.4.4 // indirect
github.com/Microsoft/go-winio v0.4.14 // indirect
github.com/containerd/containerd v1.3.7 // indirect
github.com/docker/distribution v2.7.1+incompatible // indirect
github.com/docker/docker v20.10.6+incompatible
github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/gogo/protobuf v1.3.1 // indirect
github.com/golang/protobuf v1.4.2 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/robfig/cron/v3 v3.0.1
github.com/sirupsen/logrus v1.8.1 // indirect
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 // indirect
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
google.golang.org/genproto v0.0.0-20210427215850-f767ed18ee4d // indirect
google.golang.org/grpc v1.37.0 // indirect
gotest.tools/v3 v3.0.3 // indirect
github.com/sirupsen/logrus v1.6.0 // indirect
github.com/stevvooe/resumable v0.0.0-20180830230917-22b14a53ba50 // indirect
github.com/stretchr/testify v1.5.1 // indirect
golang.org/x/net v0.0.0-20200707034311-ab3426394381
golang.org/x/sys v0.0.0-20200806125547-5acd03effb82 // indirect
google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98 // indirect
google.golang.org/grpc v1.31.0 // indirect
google.golang.org/protobuf v1.25.0 // indirect
)

144
go.sum
View File

@ -1,168 +1,129 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
git.iamthefij.com/iamthefij/slog v1.3.0 h1:4Hu5PQvDrW5e3FrTS3q2iIXW0iPvhNY/9qJsqDR3K3I=
git.iamthefij.com/iamthefij/slog v1.3.0/go.mod h1:1RUj4hcCompZkAxXCRfUX786tb3cM/Zpkn97dGfUfbg=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU=
github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Microsoft/go-winio v0.4.9 h1:3RbgqgGVqmcpbOiwrjbVtDHLlJBGF6aE+yHmNtBNsFQ=
github.com/Microsoft/go-winio v0.4.9/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/containerd/containerd v1.4.4 h1:rtRG4N6Ct7GNssATwgpvMGfnjnwfjnu/Zs9W3Ikzq+M=
github.com/containerd/containerd v1.4.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/containerd/containerd v1.3.7 h1:eFSOChY8TTcxvkzp8g+Ov1RL0MYww7XEeK0y+zqGpVc=
github.com/containerd/containerd v1.3.7/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/distribution v2.6.2+incompatible h1:4FI6af79dfCS/CYb+RRtkSHw3q1L/bnDjG1PcPZtQhM=
github.com/docker/distribution v2.6.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v20.10.6+incompatible h1:oXI3Vas8TI8Eu/EjH4srKHJBVqraSzJybhxY7Om9faQ=
github.com/docker/docker v20.10.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo=
github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible h1:iWPIG7pWIsCwT6ZtHnTUpoVMnete7O/pzd9HFE3+tn8=
github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
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.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
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 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk=
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/stevvooe/resumable v0.0.0-20180830230917-22b14a53ba50/go.mod h1:1pdIZTAHUz+HDKDVZ++5xg/duPlhKAIzw9qy42CWYp4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200806125547-5acd03effb82 h1:6cBnXxYO+CiRVrChvCosSv7magqTPbyAgz1M8iOv5wM=
golang.org/x/sys v0.0.0-20200806125547-5acd03effb82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20210427215850-f767ed18ee4d h1:XkK62R+tLAM4pyhJdBEvtb5B/hM1uTxsVIOjJm6wras=
google.golang.org/genproto v0.0.0-20210427215850-f767ed18ee4d/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98 h1:LCO0fg4kb6WwkXQXRQQgUYsFeFb5taTX5WAx5O/Vt28=
google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
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 v1.31.0 h1:T7P4R73V3SSDPhH7WW7ATbfViLtmamH0DKrP3f9AuDI=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
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=
@ -171,16 +132,11 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
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/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

74
main.go
View File

@ -8,9 +8,9 @@ import (
"strings"
"time"
"git.iamthefij.com/iamthefij/slog"
dockerTypes "github.com/docker/docker/api/types"
dockerClient "github.com/docker/docker/client"
"github.com/iamthefij/dockron/slog"
"github.com/robfig/cron/v3"
"golang.org/x/net/context"
)
@ -60,18 +60,17 @@ type ContainerStartJob struct {
// Run is executed based on the ContainerStartJob Schedule and starts the
// container
func (job ContainerStartJob) Run() {
slog.Infof("Starting: %s", job.name)
slog.Info("Starting: %s", job.name)
// Check if container is already running
containerJSON, err := job.client.ContainerInspect(
job.context,
job.containerID,
)
slog.OnErrPanicf(err, "Could not get container details for job %s", job.name)
slog.PanicOnErr(err, "Could not get container details for job %s", job.name)
if containerJSON.State.Running {
slog.Warningf("Container is already running. Skipping %s", job.name)
slog.Warning("Container is already running. Skipping %s", job.name)
return
}
@ -81,29 +80,30 @@ func (job ContainerStartJob) Run() {
job.containerID,
dockerTypes.ContainerStartOptions{},
)
slog.OnErrPanicf(err, "Could not start container for job %s", job.name)
slog.PanicOnErr(err, "Could not start container for job %s", job.name)
// Check results of job
for check := true; check; check = containerJSON.State.Running {
slog.Debugf("Still running %s", job.name)
slog.Debug("Still running %s", job.name)
containerJSON, err = job.client.ContainerInspect(
job.context,
job.containerID,
)
slog.OnErrPanicf(err, "Could not get container details for job %s", job.name)
slog.PanicOnErr(err, "Could not get container details for job %s", job.name)
time.Sleep(1 * time.Second)
}
slog.Debugf("Done execing %s. %+v", job.name, containerJSON.State)
slog.Debug("Done execing %s. %+v", job.name, containerJSON.State)
// Log exit code if failed
if containerJSON.State.ExitCode != 0 {
slog.Errorf(
slog.Error(
"Exec job %s existed with code %d",
job.name,
containerJSON.State.ExitCode,
)
}
}
// Name returns the name of the job
@ -132,16 +132,15 @@ type ContainerExecJob struct {
// Run is executed based on the ContainerStartJob Schedule and starts the
// container
func (job ContainerExecJob) Run() {
slog.Infof("Execing: %s", job.name)
slog.Info("Execing: %s", job.name)
containerJSON, err := job.client.ContainerInspect(
job.context,
job.containerID,
)
slog.OnErrPanicf(err, "Could not get container details for job %s", job.name)
slog.PanicOnErr(err, "Could not get container details for job %s", job.name)
if !containerJSON.State.Running {
slog.Warningf("Container not running. Skipping %s", job.name)
slog.Warning("Container not running. Skipping %s", job.name)
return
}
@ -152,57 +151,53 @@ func (job ContainerExecJob) Run() {
Cmd: []string{"sh", "-c", strings.TrimSpace(job.shellCommand)},
},
)
slog.OnErrPanicf(err, "Could not create container exec job for %s", job.name)
slog.PanicOnErr(err, "Could not create container exec job for %s", job.name)
err = job.client.ContainerExecStart(
job.context,
execID.ID,
dockerTypes.ExecStartCheck{},
)
slog.OnErrPanicf(err, "Could not start container exec job for %s", job.name)
slog.PanicOnErr(err, "Could not start container exec job for %s", job.name)
// Wait for job results
execInfo := dockerTypes.ContainerExecInspect{Running: true}
for execInfo.Running {
slog.Debugf("Still execing %s", job.name)
slog.Debug("Still execing %s", job.name)
execInfo, err = job.client.ContainerExecInspect(
job.context,
execID.ID,
)
slog.Debugf("Exec info: %+v", execInfo)
slog.Debug("Exec info: %+v", execInfo)
if err != nil {
// Nothing we can do if we got an error here, so let's go
slog.OnErrWarnf(err, "Could not get status for exec job %s", job.name)
slog.WarnOnErr(err, "Could not get status for exec job %s", job.name)
return
}
time.Sleep(1 * time.Second)
}
slog.Debugf("Done execing %s. %+v", job.name, execInfo)
slog.Debug("Done execing %s. %+v", job.name, execInfo)
// Log exit code if failed
if execInfo.ExitCode != 0 {
slog.Errorf("Exec job %s existed with code %d", job.name, execInfo.ExitCode)
slog.Error("Exec job %s existed with code %d", job.name, execInfo.ExitCode)
}
}
// QueryScheduledJobs queries Docker for all containers with a schedule and
// returns a list of ContainerCronJob records to be scheduled
func QueryScheduledJobs(client ContainerClient) (jobs []ContainerCronJob) {
slog.Debugf("Scanning containers for new schedules...")
slog.Debug("Scanning containers for new schedules...")
containers, err := client.ContainerList(
context.Background(),
dockerTypes.ContainerListOptions{All: true},
)
slog.OnErrPanicf(err, "Failure querying docker containers")
slog.PanicOnErr(err, "Failure querying docker containers")
for _, container := range containers {
// Add start job
if val, ok := container.Labels[schedLabel]; ok {
jobName := strings.Join(container.Names, "/")
jobs = append(jobs, ContainerStartJob{
client: client,
containerID: container.ID,
@ -214,12 +209,9 @@ func QueryScheduledJobs(client ContainerClient) (jobs []ContainerCronJob) {
// Add exec jobs
execJobs := map[string]map[string]string{}
for label, value := range container.Labels {
results := execLabelRegexp.FindStringSubmatch(label)
expectedLabelParts := 3
if len(results) == expectedLabelParts {
if len(results) == 3 {
// We've got part of a new job
jobName, jobField := results[1], results[2]
if partJob, ok := execJobs[jobName]; ok {
@ -233,18 +225,15 @@ func QueryScheduledJobs(client ContainerClient) (jobs []ContainerCronJob) {
}
}
}
for jobName, jobConfig := range execJobs {
schedule, ok := jobConfig["schedule"]
if !ok {
continue
}
shellCommand, ok := jobConfig["command"]
if !ok {
continue
}
jobs = append(jobs, ContainerExecJob{
ContainerStartJob: ContainerStartJob{
client: client,
@ -258,7 +247,7 @@ func QueryScheduledJobs(client ContainerClient) (jobs []ContainerCronJob) {
}
}
return jobs
return
}
// ScheduleJobs accepts a Cron instance and a list of jobs to schedule.
@ -275,16 +264,15 @@ func ScheduleJobs(c *cron.Cron, jobs []ContainerCronJob) {
if _, ok := existingJobs[job.UniqueName()]; ok {
// Job already exists, remove it from existing jobs so we don't
// unschedule it later
slog.Debugf("Job %s is already scheduled. Skipping", job.Name())
slog.Debug("Job %s is already scheduled. Skipping", job.Name())
delete(existingJobs, job.UniqueName())
continue
}
// Job doesn't exist yet, schedule it
_, err := c.AddJob(job.Schedule(), job)
if err == nil {
slog.Infof(
slog.Info(
"Scheduled %s (%s) with schedule '%s'\n",
job.Name(),
job.UniqueName(),
@ -292,7 +280,7 @@ func ScheduleJobs(c *cron.Cron, jobs []ContainerCronJob) {
)
} else {
// TODO: Track something for a healthcheck here
slog.Errorf(
slog.Error(
"Could not schedule %s (%s) with schedule '%s'. %v\n",
job.Name(),
job.UniqueName(),
@ -311,14 +299,14 @@ func ScheduleJobs(c *cron.Cron, jobs []ContainerCronJob) {
func main() {
// Get a Docker Client
client, err := dockerClient.NewClientWithOpts(dockerClient.FromEnv)
slog.OnErrPanicf(err, "Could not create Docker client")
if err != nil {
panic(err)
}
// Read interval for polling Docker
var watchInterval time.Duration
showVersion := flag.Bool("version", false, "Display the version of dockron and exit")
flag.DurationVar(&watchInterval, "watch", defaultWatchInterval, "Interval used to poll Docker for changes")
var showVersion = flag.Bool("version", false, "Display the version of dockron and exit")
flag.BoolVar(&slog.DebugLevel, "debug", false, "Show debug logs")
flag.Parse()

View File

@ -1,7 +1,6 @@
package main
import (
"errors"
"fmt"
"log"
"reflect"
@ -30,8 +29,6 @@ var (
},
},
}
errGeneric = errors.New("error")
)
// FakeCall represents a faked method call
@ -78,7 +75,6 @@ func (fakeClient *FakeDockerClient) ContainerStart(context context.Context, cont
if results[0] != nil {
e = results[0].(error)
}
return
}
@ -87,11 +83,9 @@ func (fakeClient *FakeDockerClient) ContainerList(context context.Context, optio
if results[0] != nil {
c = results[0].([]dockerTypes.Container)
}
if results[1] != nil {
e = results[1].(error)
}
return
}
@ -100,11 +94,9 @@ func (fakeClient *FakeDockerClient) ContainerExecCreate(ctx context.Context, con
if results[0] != nil {
r = results[0].(dockerTypes.IDResponse)
}
if results[1] != nil {
e = results[1].(error)
}
return
}
@ -113,7 +105,6 @@ func (fakeClient *FakeDockerClient) ContainerExecStart(ctx context.Context, exec
if results[0] != nil {
e = results[0].(error)
}
return
}
@ -122,11 +113,9 @@ func (fakeClient *FakeDockerClient) ContainerExecInspect(ctx context.Context, ex
if results[0] != nil {
r = results[0].(dockerTypes.ContainerExecInspect)
}
if results[1] != nil {
e = results[1].(error)
}
return
}
@ -135,11 +124,9 @@ func (fakeClient *FakeDockerClient) ContainerInspect(ctx context.Context, contai
if results[0] != nil {
r = results[0].(dockerTypes.ContainerJSON)
}
if results[1] != nil {
e = results[1].(error)
}
return
}
@ -666,8 +653,8 @@ func TestDoLoop(t *testing.T) {
// to a subpackage that offers a single function for interfacing with the
// Docker client to start or exec a container so that Dockron needn't care.
func TestRunExecJobs(t *testing.T) {
var jobContext context.Context
var jobContext context.Context
jobContainerID := "container_id"
jobCommand := "true"
@ -682,7 +669,7 @@ func TestRunExecJobs(t *testing.T) {
client: &FakeDockerClient{
FakeResults: map[string][]FakeResult{
"ContainerInspect": []FakeResult{
FakeResult{nil, errGeneric},
FakeResult{nil, fmt.Errorf("error")},
},
},
},
@ -716,7 +703,7 @@ func TestRunExecJobs(t *testing.T) {
FakeResult{runningContainerInfo, nil},
},
"ContainerExecCreate": []FakeResult{
FakeResult{nil, errGeneric},
FakeResult{nil, fmt.Errorf("fail")},
},
},
},
@ -747,7 +734,7 @@ func TestRunExecJobs(t *testing.T) {
FakeResult{dockerTypes.IDResponse{ID: "id"}, nil},
},
"ContainerExecStart": []FakeResult{
FakeResult{errGeneric},
FakeResult{fmt.Errorf("fail")},
},
},
},
@ -784,7 +771,7 @@ func TestRunExecJobs(t *testing.T) {
FakeResult{nil},
},
"ContainerExecInspect": []FakeResult{
FakeResult{nil, errGeneric},
FakeResult{nil, fmt.Errorf("fail")},
},
},
},
@ -890,7 +877,6 @@ func TestRunExecJobs(t *testing.T) {
// Docker client to start or exec a container so that Dockron needn't care.
func TestRunStartJobs(t *testing.T) {
var jobContext context.Context
jobContainerID := "container_id"
cases := []struct {
@ -904,7 +890,7 @@ func TestRunStartJobs(t *testing.T) {
client: &FakeDockerClient{
FakeResults: map[string][]FakeResult{
"ContainerInspect": []FakeResult{
FakeResult{nil, errGeneric},
FakeResult{nil, fmt.Errorf("error")},
},
},
},
@ -937,7 +923,7 @@ func TestRunStartJobs(t *testing.T) {
"ContainerInspect": []FakeResult{
FakeResult{stoppedContainerInfo, nil},
},
"ContainerStart": []FakeResult{FakeResult{errGeneric}},
"ContainerStart": []FakeResult{FakeResult{fmt.Errorf("fail")}},
},
},
expectedCalls: map[string][]FakeCall{
@ -950,7 +936,7 @@ func TestRunStartJobs(t *testing.T) {
},
},
{
name: "Successfully start a container",
name: "Succesfully start a container",
client: &FakeDockerClient{
FakeResults: map[string][]FakeResult{
"ContainerInspect": []FakeResult{
@ -988,13 +974,14 @@ func TestRunStartJobs(t *testing.T) {
defer func() {
// Recover from panics, if there were any
_ = recover()
recover()
c.client.AssertFakeCalls(t, c.expectedCalls, "Failed")
}()
job.Run()
if c.expectPanic {
t.Errorf("Expected panic but got none")
}
})
}
}

54
slog/Readme.md Normal file
View File

@ -0,0 +1,54 @@
# slog
A super simple go logger
I know there are many go loggers out there that offer various logging features such as file rotation, granular verbosity settings, colored and JSON output, etc.
_Slog is not one of them._
Slog lets you hide or show debug logs as well as provides a simpler way to log messages with Warning and Error prefixes for consistency.
Also provided are a few simple methods for handling returned `error` variables, logging them out and optionally panicing or fatally exiting.
## Documentation
package slog // import "github.com/iamthefij/dockron/slog"
Package slog is a super simple logger that allows a few convenience methods
for handling debug vs warning/error logs. It also adds a few conveniences
for handling errors.
VARIABLES
var (
// DebugLevel indicates if we should log at the debug level
DebugLevel = true
)
FUNCTIONS
func Debug(format string, v ...interface{})
Debug will log with a DEBUG prefix if DebugLevel is se
func Error(format string, v ...interface{})
Error will log with a ERROR prefix
func FatalOnErr(err error, format string, v ...interface{})
FatalOnErr if error provided, will log out details of an error and exi
func Info(format string, v ...interface{})
Info formats logs with an INFO prefix
func Log(format string, v ...interface{})
Log formats logs directly to the main logger
func PanicOnErr(err error, format string, v ...interface{})
PanicOnErr if error provided, will log out details of an error and exi
func SetFlags(flag int)
SetFlags allows changing the logger flags using flags found in `log`
func WarnOnErr(err error, format string, v ...interface{})
WarnOnErr if error provided, will provide a warning if an error is provided
func Warning(format string, v ...interface{})
Warning will log with a WARNING prefix

8
slog/add-docs-to-readme.sh Executable file
View File

@ -0,0 +1,8 @@
#! /bin/bash
set -e
slogdir=$(dirname "$0")
readme="$slogdir/Readme.md"
awk '/## Documentation/ {print ; exit} {print}' "$readme" > "$readme.tmp" && go doc -all slog | sed "s/^/ /;s/[ \t]*$//" >> "$readme.tmp"
mv "$readme.tmp" "$readme"

90
slog/slog.go Normal file
View File

@ -0,0 +1,90 @@
// Package slog is a super simple logger that allows a few convenience methods
// for handling debug vs warning/error logs. It also adds a few conveniences for
// handling errors.
package slog
import (
"log"
"os"
)
var (
// DebugLevel indicates if we should log at the debug level
DebugLevel = true
// Default set of flags to use
defaultFlags = log.LstdFlags | log.Lmsgprefix
// Loggers for various levels. Prefixes are padded to align logged content
loggerInfo = log.New(os.Stderr, "INFO ", defaultFlags)
loggerWarning = log.New(os.Stderr, "WARNING ", defaultFlags)
loggerError = log.New(os.Stderr, "ERROR ", defaultFlags)
loggerDebug = log.New(os.Stderr, "DEBUG ", defaultFlags)
// Convenience for calling functions for all loggers in one method
allLoggers = []*log.Logger{
loggerInfo,
loggerWarning,
loggerError,
loggerDebug,
}
)
// SetFlags allows changing the logger flags using flags found in `log`
func SetFlags(flag int) {
for _, logger := range allLoggers {
logger.SetFlags(flag)
}
}
// Log formats logs directly to the main logger
func Log(format string, v ...interface{}) {
log.Printf(format, v...)
}
// Info formats logs with an INFO prefix
func Info(format string, v ...interface{}) {
loggerInfo.Printf(format, v...)
}
// Warning will log with a WARNING prefix
func Warning(format string, v ...interface{}) {
loggerWarning.Printf(format, v...)
}
// Error will log with a ERROR prefix
func Error(format string, v ...interface{}) {
loggerError.Printf(format, v...)
}
// Debug will log with a DEBUG prefix if DebugLevel is set
func Debug(format string, v ...interface{}) {
if !DebugLevel {
return
}
loggerDebug.Printf(format, v...)
}
// WarnOnErr if error provided, will provide a warning if an error is provided
func WarnOnErr(err error, format string, v ...interface{}) {
if err != nil {
loggerWarning.Printf(format, v...)
loggerError.Print(err)
}
}
// FatalOnErr if error provided, will log out details of an error and exit
func FatalOnErr(err error, format string, v ...interface{}) {
if err != nil {
loggerError.Printf(format, v...)
loggerError.Fatal(err)
}
}
// PanicOnErr if error provided, will log out details of an error and exit
func PanicOnErr(err error, format string, v ...interface{}) {
if err != nil {
loggerError.Printf(format, v...)
loggerError.Panic(err)
}
}