Compare commits
4 Commits
master
...
drone-new-
Author | SHA1 | Date | |
---|---|---|---|
17291a846a | |||
36813d0c27 | |||
164521d745 | |||
c24bdad381 |
229
.drone.yml
229
.drone.yml
@ -3,118 +3,131 @@ kind: pipeline
|
|||||||
name: test
|
name: test
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: test
|
# - name: test
|
||||||
image: golang:1.22
|
# image: golang:1.15
|
||||||
commands:
|
|
||||||
- make test
|
|
||||||
|
|
||||||
- name: check
|
|
||||||
image: iamthefij/drone-pre-commit:personal
|
|
||||||
environment:
|
|
||||||
SKIP: docker-compose-check
|
|
||||||
|
|
||||||
# - name: itest
|
|
||||||
# image: docker/compose:alpine-1.26.2
|
|
||||||
# environment:
|
|
||||||
# VERSION: ${DRONE_TAG:-${DRONE_COMMIT}}
|
|
||||||
# commands:
|
# commands:
|
||||||
# - apk add make bash
|
# - make test
|
||||||
# - make itest
|
|
||||||
|
|
||||||
---
|
# - name: check
|
||||||
kind: pipeline
|
# image: python:3
|
||||||
name: publish
|
# 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
|
||||||
|
|
||||||
depends_on:
|
- name: itest
|
||||||
- test
|
image: golang:1.15
|
||||||
|
volumes:
|
||||||
trigger:
|
- name: itest_out
|
||||||
event:
|
path: /out
|
||||||
- push
|
|
||||||
- tag
|
|
||||||
refs:
|
|
||||||
- refs/heads/master
|
|
||||||
- refs/tags/v*
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: build
|
|
||||||
image: golang:1.22
|
|
||||||
environment:
|
|
||||||
VERSION: ${DRONE_TAG:-${DRONE_COMMIT}}
|
|
||||||
commands:
|
commands:
|
||||||
- make build-linux-static
|
- echo "start" > /out/start_result.txt
|
||||||
|
- echo "start" > /out/exec_result.txt
|
||||||
- name: push image - arm
|
- timeout 70 go run . -watch 10s -debug
|
||||||
image: plugins/docker
|
|
||||||
settings:
|
|
||||||
repo: iamthefij/dockron
|
|
||||||
auto_tag: true
|
|
||||||
auto_tag_suffix: linux-arm
|
|
||||||
username:
|
|
||||||
from_secret: docker_username
|
|
||||||
password:
|
|
||||||
from_secret: docker_password
|
|
||||||
build_args:
|
|
||||||
- ARCH=arm
|
|
||||||
- REPO=arm32v7
|
|
||||||
|
|
||||||
- name: push image - arm64
|
|
||||||
image: plugins/docker
|
|
||||||
settings:
|
|
||||||
repo: iamthefij/dockron
|
|
||||||
auto_tag: true
|
|
||||||
auto_tag_suffix: linux-arm64
|
|
||||||
username:
|
|
||||||
from_secret: docker_username
|
|
||||||
password:
|
|
||||||
from_secret: docker_password
|
|
||||||
build_args:
|
|
||||||
- ARCH=arm64
|
|
||||||
- REPO=arm64v8
|
|
||||||
|
|
||||||
- name: push image - amd64
|
|
||||||
image: plugins/docker
|
|
||||||
settings:
|
|
||||||
repo: iamthefij/dockron
|
|
||||||
auto_tag: true
|
|
||||||
auto_tag_suffix: linux-amd64
|
|
||||||
username:
|
|
||||||
from_secret: docker_username
|
|
||||||
password:
|
|
||||||
from_secret: docker_password
|
|
||||||
|
|
||||||
- name: publish manifest
|
|
||||||
image: plugins/manifest
|
|
||||||
settings:
|
|
||||||
spec: manifest.tmpl
|
|
||||||
auto_tag: true
|
|
||||||
ignore_missing: true
|
|
||||||
username:
|
|
||||||
from_secret: docker_username
|
|
||||||
password:
|
|
||||||
from_secret: docker_password
|
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- name: itest_out
|
||||||
|
temp: {}
|
||||||
|
# ---
|
||||||
|
# kind: pipeline
|
||||||
|
# name: publish
|
||||||
|
#
|
||||||
|
# depends_on:
|
||||||
|
# - test
|
||||||
|
#
|
||||||
|
# trigger:
|
||||||
|
# event:
|
||||||
|
# - push
|
||||||
|
# - tag
|
||||||
|
# refs:
|
||||||
|
# - refs/heads/master
|
||||||
|
# - refs/tags/v*
|
||||||
|
#
|
||||||
|
# steps:
|
||||||
|
# - name: build
|
||||||
|
# image: golang:1.15
|
||||||
|
# environment:
|
||||||
|
# VERSION: ${DRONE_TAG:-${DRONE_COMMIT}}
|
||||||
|
# commands:
|
||||||
|
# - make build-linux-static
|
||||||
|
#
|
||||||
|
# - name: push image - arm
|
||||||
|
# image: plugins/docker
|
||||||
|
# settings:
|
||||||
|
# repo: iamthefij/dockron
|
||||||
|
# auto_tag: true
|
||||||
|
# auto_tag_suffix: linux-arm
|
||||||
|
# username:
|
||||||
|
# from_secret: docker_username
|
||||||
|
# password:
|
||||||
|
# from_secret: docker_password
|
||||||
|
# build_args:
|
||||||
|
# - ARCH=arm
|
||||||
|
# - REPO=arm32v7
|
||||||
|
#
|
||||||
|
# - name: push image - arm64
|
||||||
|
# image: plugins/docker
|
||||||
|
# settings:
|
||||||
|
# repo: iamthefij/dockron
|
||||||
|
# auto_tag: true
|
||||||
|
# auto_tag_suffix: linux-arm64
|
||||||
|
# username:
|
||||||
|
# from_secret: docker_username
|
||||||
|
# password:
|
||||||
|
# from_secret: docker_password
|
||||||
|
# build_args:
|
||||||
|
# - ARCH=arm64
|
||||||
|
# - REPO=arm64v8
|
||||||
|
#
|
||||||
|
# - name: push image - amd64
|
||||||
|
# image: plugins/docker
|
||||||
|
# settings:
|
||||||
|
# repo: iamthefij/dockron
|
||||||
|
# auto_tag: true
|
||||||
|
# auto_tag_suffix: linux-amd64
|
||||||
|
# username:
|
||||||
|
# from_secret: docker_username
|
||||||
|
# password:
|
||||||
|
# from_secret: docker_password
|
||||||
|
#
|
||||||
|
# - name: publish manifest
|
||||||
|
# image: plugins/manifest
|
||||||
|
# settings:
|
||||||
|
# spec: manifest.tmpl
|
||||||
|
# auto_tag: true
|
||||||
|
# ignore_missing: true
|
||||||
|
# username:
|
||||||
|
# from_secret: docker_username
|
||||||
|
# password:
|
||||||
|
# from_secret: docker_password
|
||||||
|
#
|
||||||
|
# ---
|
||||||
|
# kind: pipeline
|
||||||
|
# name: notify
|
||||||
|
#
|
||||||
|
# depends_on:
|
||||||
|
# - test
|
||||||
|
# - publish
|
||||||
|
#
|
||||||
|
# trigger:
|
||||||
|
# status:
|
||||||
|
# - failure
|
||||||
|
#
|
||||||
|
# steps:
|
||||||
|
#
|
||||||
|
# - name: notify
|
||||||
|
# image: drillster/drone-email
|
||||||
|
# settings:
|
||||||
|
# host:
|
||||||
|
# from_secret: SMTP_HOST # pragma: whitelist secret
|
||||||
|
# username:
|
||||||
|
# from_secret: SMTP_USER # pragma: whitelist secret
|
||||||
|
# password:
|
||||||
|
# from_secret: SMTP_PASS # pragma: whitelist secret
|
||||||
|
# from: drone@iamthefij.com
|
||||||
---
|
---
|
||||||
kind: pipeline
|
kind: signature
|
||||||
name: notify
|
hmac: 1823edf861345f607810aba849580e6b5a24ee5248d44d1b1fa63adccf05c6ee
|
||||||
|
|
||||||
depends_on:
|
...
|
||||||
- test
|
|
||||||
- publish
|
|
||||||
|
|
||||||
trigger:
|
|
||||||
status:
|
|
||||||
- failure
|
|
||||||
|
|
||||||
steps:
|
|
||||||
|
|
||||||
- name: notify
|
|
||||||
image: drillster/drone-email
|
|
||||||
settings:
|
|
||||||
host:
|
|
||||||
from_secret: SMTP_HOST # pragma: whitelist secret
|
|
||||||
username:
|
|
||||||
from_secret: SMTP_USER # pragma: whitelist secret
|
|
||||||
password:
|
|
||||||
from_secret: SMTP_PASS # pragma: whitelist secret
|
|
||||||
from: drone@iamthefij.com
|
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
---
|
|
||||||
linters:
|
|
||||||
enable:
|
|
||||||
- errname
|
|
||||||
- errorlint
|
|
||||||
- exhaustive
|
|
||||||
- gofumpt
|
|
||||||
- goimports
|
|
||||||
- goprintffuncname
|
|
||||||
- misspell
|
|
||||||
- gomnd
|
|
||||||
- tagliatelle
|
|
||||||
- tenv
|
|
||||||
- testpackage
|
|
||||||
- thelper
|
|
||||||
- tparallel
|
|
||||||
- unconvert
|
|
||||||
- wrapcheck
|
|
||||||
- wsl
|
|
||||||
disable:
|
|
||||||
- gochecknoglobals
|
|
||||||
|
|
||||||
linters-settings:
|
|
||||||
gosec:
|
|
||||||
excludes:
|
|
||||||
- G204
|
|
||||||
tagliatelle:
|
|
||||||
case:
|
|
||||||
rules:
|
|
||||||
yaml: snake
|
|
||||||
|
|
||||||
issues:
|
|
||||||
exclude-rules:
|
|
||||||
- path: _test\.go
|
|
||||||
linters:
|
|
||||||
- gosec
|
|
@ -1,22 +1,21 @@
|
|||||||
---
|
---
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.6.0
|
rev: v2.4.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-added-large-files
|
- id: check-added-large-files
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
- id: check-merge-conflict
|
- id: check-merge-conflict
|
||||||
- repo: https://github.com/golangci/golangci-lint
|
- repo: git://github.com/dnephin/pre-commit-golang
|
||||||
rev: v1.52.2
|
rev: v0.3.5
|
||||||
hooks:
|
hooks:
|
||||||
- id: golangci-lint
|
- id: go-fmt
|
||||||
args: ["--timeout=5m"]
|
- id: go-imports
|
||||||
|
# - id: gometalinter
|
||||||
|
# - id: golangci-lint
|
||||||
- repo: https://github.com/IamTheFij/docker-pre-commit
|
- repo: https://github.com/IamTheFij/docker-pre-commit
|
||||||
rev: v3.0.1
|
rev: v2.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: docker-compose-check
|
- id: docker-compose-check
|
||||||
- repo: https://github.com/hadolint/hadolint
|
- id: hadolint-system
|
||||||
rev: v2.12.0
|
|
||||||
hooks:
|
|
||||||
- id: hadolint
|
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
ARG REPO=library
|
ARG REPO=library
|
||||||
FROM golang:1.22-alpine AS builder
|
FROM golang:1.15-alpine AS builder
|
||||||
|
|
||||||
# hadolint ignore=DL3018
|
# hadolint ignore=DL3018
|
||||||
RUN apk add --no-cache git && \
|
RUN apk add --no-cache git
|
||||||
mkdir /app
|
|
||||||
|
RUN mkdir /app
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY ./go.mod ./go.sum /app/
|
COPY ./go.mod ./go.sum /app/
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|
||||||
COPY ./main.go /app/
|
COPY ./main.go /app/
|
||||||
|
COPY ./slog /app/slog
|
||||||
|
|
||||||
ARG ARCH=amd64
|
ARG ARCH=amd64
|
||||||
ARG VERSION=dev
|
ARG VERSION=dev
|
||||||
|
71
Makefile
71
Makefile
@ -1,8 +1,7 @@
|
|||||||
OUTPUT ?= dockron
|
DOCKER_TAG ?= dockron-dev-${USER}
|
||||||
DOCKER_TAG ?= $(OUTPUT)-dev-$(USER)
|
|
||||||
GIT_TAG_NAME := $(shell git tag -l --contains HEAD)
|
GIT_TAG_NAME := $(shell git tag -l --contains HEAD)
|
||||||
GIT_SHA := $(shell git rev-parse 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
|
GOFILES = *.go go.mod go.sum
|
||||||
|
|
||||||
@ -43,45 +42,45 @@ check:
|
|||||||
pre-commit run --all-files
|
pre-commit run --all-files
|
||||||
|
|
||||||
# Output target
|
# Output target
|
||||||
$(OUTPUT): $(GOFILES)
|
dockron: $(GOFILES)
|
||||||
@echo Version: $(VERSION)
|
@echo Version: $(VERSION)
|
||||||
go build -ldflags '-X "main.version=$(VERSION)"' -o $(OUTPUT)
|
go build -ldflags '-X "main.version=${VERSION}"' -o dockron
|
||||||
|
|
||||||
# Alias for building
|
# Alias for building
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build: $(OUTPUT)
|
build: dockron
|
||||||
|
|
||||||
$(OUTPUT)-darwin-amd64: $(GOFILES)
|
dockron-darwin-amd64: $(GOFILES)
|
||||||
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 \
|
GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 \
|
||||||
go build -ldflags '-X "main.version=$(VERSION)"' -a -installsuffix nocgo \
|
go build -ldflags '-X "main.version=${VERSION}"' -a -installsuffix nocgo \
|
||||||
-o $(OUTPUT)-darwin-amd64
|
-o dockron-darwin-amd64
|
||||||
|
|
||||||
$(OUTPUT)-linux-amd64: $(GOFILES)
|
dockron-linux-amd64: $(GOFILES)
|
||||||
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 \
|
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 \
|
||||||
go build -ldflags '-X "main.version=$(VERSION)"' -a -installsuffix nocgo \
|
go build -ldflags '-X "main.version=${VERSION}"' -a -installsuffix nocgo \
|
||||||
-o $(OUTPUT)-linux-amd64
|
-o dockron-linux-amd64
|
||||||
|
|
||||||
$(OUTPUT)-linux-arm: $(GOFILES)
|
dockron-linux-arm: $(GOFILES)
|
||||||
GOOS=linux GOARCH=arm CGO_ENABLED=0 \
|
GOOS=linux GOARCH=arm CGO_ENABLED=0 \
|
||||||
go build -ldflags '-X "main.version=$(VERSION)"' -a -installsuffix nocgo \
|
go build -ldflags '-X "main.version=${VERSION}"' -a -installsuffix nocgo \
|
||||||
-o $(OUTPUT)-linux-arm
|
-o dockron-linux-arm
|
||||||
|
|
||||||
$(OUTPUT)-linux-arm64: $(GOFILES)
|
dockron-linux-arm64: $(GOFILES)
|
||||||
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 \
|
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 \
|
||||||
go build -ldflags '-X "main.version=$(VERSION)"' -a -installsuffix nocgo \
|
go build -ldflags '-X "main.version=${VERSION}"' -a -installsuffix nocgo \
|
||||||
-o $(OUTPUT)-linux-arm64
|
-o dockron-linux-arm64
|
||||||
|
|
||||||
.PHONY: build-linux-static
|
.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
|
.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
|
# Cleans all build artifacts
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
rm -f $(OUTPUT)
|
rm -f dockron
|
||||||
rm -f $(OUTPUT)-linux-*
|
rm -f dockron-linux-*
|
||||||
|
|
||||||
# Cleans vendor directory
|
# Cleans vendor directory
|
||||||
.PHONY: clean-vendor
|
.PHONY: clean-vendor
|
||||||
@ -89,17 +88,17 @@ clean-vendor:
|
|||||||
rm -fr ./vendor
|
rm -fr ./vendor
|
||||||
|
|
||||||
.PHONY: docker-build
|
.PHONY: docker-build
|
||||||
docker-build: $(OUTPUT)-linux-amd64
|
docker-build: dockron-linux-amd64
|
||||||
docker build . -t $(DOCKER_TAG)-linux-amd64
|
docker build . -t ${DOCKER_TAG}-linux-amd64
|
||||||
|
|
||||||
# Cross build for arm architechtures
|
# Cross build for arm architechtures
|
||||||
.PHONY: docker-build-arm
|
.PHONY: docker-build-arm
|
||||||
docker-build-arm: $(OUTPUT)-linux-arm
|
docker-build-arm: dockron-linux-arm
|
||||||
docker build --build-arg REPO=arm32v7 --build-arg ARCH=arm . -t $(DOCKER_TAG)-linux-arm
|
docker build --build-arg REPO=arm32v7 --build-arg ARCH=arm . -t ${DOCKER_TAG}-linux-arm
|
||||||
|
|
||||||
.PHONY: docker-build-arm
|
.PHONY: docker-build-arm
|
||||||
docker-build-arm64: $(OUTPUT)-linux-arm64
|
docker-build-arm64: dockron-linux-arm64
|
||||||
docker build --build-arg REPO=arm64v8 --build-arg ARCH=arm64 . -t $(DOCKER_TAG)-linux-arm64
|
docker build --build-arg REPO=arm64v8 --build-arg ARCH=arm64 . -t ${DOCKER_TAG}-linux-arm64
|
||||||
|
|
||||||
.PHONY: docker-run
|
.PHONY: docker-run
|
||||||
docker-run: docker-build
|
docker-run: docker-build
|
||||||
@ -108,30 +107,30 @@ docker-run: docker-build
|
|||||||
# Cross run on host architechture
|
# Cross run on host architechture
|
||||||
.PHONY: docker-run-arm
|
.PHONY: docker-run-arm
|
||||||
docker-run-arm: docker-build-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
|
.PHONY: docker-run-arm64
|
||||||
docker-run-arm64: docker-build-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
|
# Multi stage builds
|
||||||
.PHONY: docker-staged-build
|
.PHONY: docker-staged-build
|
||||||
docker-staged-build:
|
docker-staged-build:
|
||||||
docker build --build-arg VERSION=$(VERSION) \
|
docker build --build-arg VERSION=${VERSION} \
|
||||||
-t $(DOCKER_TAG)-linux-amd64 \
|
-t ${DOCKER_TAG}-linux-amd64 \
|
||||||
-f Dockerfile.multi-stage .
|
-f Dockerfile.multi-stage .
|
||||||
|
|
||||||
# Cross build for arm architechtures
|
# Cross build for arm architechtures
|
||||||
.PHONY: docker-staged-build-arm
|
.PHONY: docker-staged-build-arm
|
||||||
docker-staged-build-arm:
|
docker-staged-build-arm:
|
||||||
docker build --build-arg VERSION=$(VERSION) \
|
docker build --build-arg VERSION=${VERSION} \
|
||||||
--build-arg REPO=arm32v7 --build-arg ARCH=arm -t $(DOCKER_TAG)-linux-arm \
|
--build-arg REPO=arm32v7 --build-arg ARCH=arm -t ${DOCKER_TAG}-linux-arm \
|
||||||
-f Dockerfile.multi-stage .
|
-f Dockerfile.multi-stage .
|
||||||
|
|
||||||
.PHONY: docker-staged-build-arm
|
.PHONY: docker-staged-build-arm
|
||||||
docker-staged-build-arm64:
|
docker-staged-build-arm64:
|
||||||
docker build --build-arg VERSION=$(VERSION) \
|
docker build --build-arg VERSION=${VERSION} \
|
||||||
--build-arg REPO=arm64v8 --build-arg ARCH=arm64 -t $(DOCKER_TAG)-linux-arm64 \
|
--build-arg REPO=arm64v8 --build-arg ARCH=arm64 -t ${DOCKER_TAG}-linux-arm64 \
|
||||||
-f Dockerfile.multi-stage .
|
-f Dockerfile.multi-stage .
|
||||||
|
|
||||||
.PHONY: docker-example
|
.PHONY: docker-example
|
||||||
|
12
README.md
12
README.md
@ -24,16 +24,6 @@ From either an `amd64`, `arm`, or `arm64` machine, you can run Dockron using:
|
|||||||
|
|
||||||
docker run -v /var/run/docker.sock:/var/run/docker.sock:ro iamthefij/dockron -watch
|
docker run -v /var/run/docker.sock:/var/run/docker.sock:ro iamthefij/dockron -watch
|
||||||
|
|
||||||
### Getting a Docker API Version error?
|
|
||||||
|
|
||||||
You might see something like the following error when Dockron connects to the Docker API
|
|
||||||
|
|
||||||
```
|
|
||||||
Error response from daemon: client version 1.47 is too new. Maximum supported API version is 1.45
|
|
||||||
```
|
|
||||||
|
|
||||||
This is because the API client library is newer than the version of the Docker API on your host. You can tell the Dockron API Client to use a compatible version by specifying `DOCKER_API_VERSION=1.45`, where the version you specify matches the API version shown when you run `docker version`. If you are running Dockron in Docker, make sure you add this to your compose environment or otherwise pass it to the container.
|
|
||||||
|
|
||||||
### Scheduling a container
|
### Scheduling a container
|
||||||
|
|
||||||
First, be sure your container is something that is not long running and will actually exit when complete. This is for batch runs and not keeping a service running. Docker should be able to do that on it's own with a restart policy.
|
First, be sure your container is something that is not long running and will actually exit when complete. This is for batch runs and not keeping a service running. Docker should be able to do that on it's own with a restart policy.
|
||||||
@ -50,7 +40,7 @@ Eg.
|
|||||||
- "dockron.dates.schedule=* * * * *"
|
- "dockron.dates.schedule=* * * * *"
|
||||||
- "dockron.dates.command=date"
|
- "dockron.dates.command=date"
|
||||||
|
|
||||||
_Note: Exec jobs will log their output to Dockron. There is also currently no way to health check these._
|
_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
|
### Cron Expression Formatting
|
||||||
|
|
||||||
|
49
go.mod
49
go.mod
@ -1,39 +1,26 @@
|
|||||||
module github.com/iamthefij/dockron
|
module github.com/iamthefij/dockron
|
||||||
|
|
||||||
go 1.22
|
go 1.12
|
||||||
|
|
||||||
toolchain go1.22.7
|
|
||||||
|
|
||||||
require (
|
|
||||||
git.iamthefij.com/iamthefij/slog v1.3.0
|
|
||||||
github.com/docker/docker v27.3.1+incompatible
|
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
|
||||||
golang.org/x/net v0.29.0
|
|
||||||
)
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Microsoft/go-winio v0.4.14 // indirect
|
github.com/Microsoft/go-winio v0.4.14 // indirect
|
||||||
github.com/containerd/log v0.1.0 // indirect
|
github.com/containerd/containerd v1.3.7 // indirect
|
||||||
github.com/distribution/reference v0.6.0 // indirect
|
github.com/docker/distribution v2.7.1+incompatible // indirect
|
||||||
github.com/docker/go-connections v0.5.0 // indirect
|
github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-connections v0.4.0 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/docker/go-units v0.4.0 // indirect
|
||||||
github.com/go-logr/logr v1.4.2 // indirect
|
github.com/gogo/protobuf v1.3.1 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/golang/protobuf v1.4.2 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
|
||||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
|
||||||
github.com/moby/term v0.5.0 // indirect
|
|
||||||
github.com/morikuni/aec v1.0.0 // indirect
|
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 // indirect
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
go.opentelemetry.io/otel v1.30.0 // indirect
|
github.com/sirupsen/logrus v1.6.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0 // indirect
|
github.com/stevvooe/resumable v0.0.0-20180830230917-22b14a53ba50 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.30.0 // indirect
|
github.com/stretchr/testify v1.5.1 // indirect
|
||||||
go.opentelemetry.io/otel/sdk v1.30.0 // indirect
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381
|
||||||
go.opentelemetry.io/otel/trace v1.30.0 // indirect
|
golang.org/x/sys v0.0.0-20200806125547-5acd03effb82 // indirect
|
||||||
golang.org/x/sys v0.25.0 // indirect
|
google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98 // indirect
|
||||||
golang.org/x/time v0.6.0 // indirect
|
google.golang.org/grpc v1.31.0 // indirect
|
||||||
gotest.tools/v3 v3.5.1 // indirect
|
google.golang.org/protobuf v1.25.0 // indirect
|
||||||
)
|
)
|
||||||
|
217
go.sum
217
go.sum
@ -1,127 +1,142 @@
|
|||||||
git.iamthefij.com/iamthefij/slog v1.3.0 h1:4Hu5PQvDrW5e3FrTS3q2iIXW0iPvhNY/9qJsqDR3K3I=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
git.iamthefij.com/iamthefij/slog v1.3.0/go.mod h1:1RUj4hcCompZkAxXCRfUX786tb3cM/Zpkn97dGfUfbg=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
github.com/Microsoft/go-winio v0.4.9 h1:3RbgqgGVqmcpbOiwrjbVtDHLlJBGF6aE+yHmNtBNsFQ=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
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 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
|
||||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
github.com/containerd/containerd v1.3.7 h1:eFSOChY8TTcxvkzp8g+Ov1RL0MYww7XEeK0y+zqGpVc=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
github.com/docker/distribution v2.6.2+incompatible h1:4FI6af79dfCS/CYb+RRtkSHw3q1L/bnDjG1PcPZtQhM=
|
||||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
github.com/docker/distribution v2.6.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI=
|
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
||||||
github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo=
|
||||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible h1:iWPIG7pWIsCwT6ZtHnTUpoVMnete7O/pzd9HFE3+tn8=
|
||||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
|
||||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
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/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/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/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
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.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
|
||||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
|
||||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
|
||||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
|
||||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
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/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
||||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
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.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
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/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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs=
|
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0/go.mod h1:DQAwmETtZV00skUwgD6+0U89g80NKsJE3DCKeLLPQMI=
|
|
||||||
go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts=
|
|
||||||
go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc=
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 h1:lsInsfvhVIfOI6qHVyysXMNDnjO9Npvl7tlDPJFBVd4=
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0/go.mod h1:KQsVNh4OjgjTG0G6EiNi1jVpnaeeKsKMRwbLN+f1+8M=
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0 h1:umZgi92IyxfXd/l4kaDhnKgY8rnN/cZcF1LKc6I8OQ8=
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0/go.mod h1:4lVs6obhSVRb1EW5FhOuBTyiQhtRtAnnva9vD3yRfq8=
|
|
||||||
go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w=
|
|
||||||
go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ=
|
|
||||||
go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE=
|
|
||||||
go.opentelemetry.io/otel/sdk v1.30.0/go.mod h1:p14X4Ok8S+sygzblytT1nqG98QG2KYKv++HE0LY/mhg=
|
|
||||||
go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc=
|
|
||||||
go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o=
|
|
||||||
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
|
|
||||||
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
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/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
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/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-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-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
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-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/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
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-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
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/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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
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/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
google.golang.org/grpc v1.66.1 h1:hO5qAXR19+/Z44hmvIM4dQFMSYX9XcWsByfoxutBpAM=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/grpc v1.66.1/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
|
google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98 h1:LCO0fg4kb6WwkXQXRQQgUYsFeFb5taTX5WAx5O/Vt28=
|
||||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
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=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
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=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
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=
|
||||||
|
@ -9,8 +9,6 @@ services:
|
|||||||
command: ["-watch", "10s", "-debug"]
|
command: ["-watch", "10s", "-debug"]
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
environment:
|
|
||||||
DOCKER_API_VERSION: 1.45
|
|
||||||
|
|
||||||
start_echoer:
|
start_echoer:
|
||||||
image: busybox:latest
|
image: busybox:latest
|
||||||
@ -29,4 +27,4 @@ services:
|
|||||||
labels:
|
labels:
|
||||||
# Execute every minute
|
# Execute every minute
|
||||||
- 'dockron.test.schedule=* * * * *'
|
- 'dockron.test.schedule=* * * * *'
|
||||||
- 'dockron.test.command=echo ok | tee /result.txt && echo "Yay!"'
|
- 'dockron.test.command=echo ok >> /result.txt'
|
||||||
|
@ -17,31 +17,20 @@ function main() {
|
|||||||
echo "start" > ./exec_result.txt
|
echo "start" > ./exec_result.txt
|
||||||
|
|
||||||
# Clean old containers
|
# Clean old containers
|
||||||
docker compose down || true
|
docker-compose down || true
|
||||||
# Start containers
|
# Start containers
|
||||||
echo "Starting containers"
|
echo "Starting containers"
|
||||||
docker compose up -d --build
|
docker-compose up -d --build
|
||||||
|
echo "Containers started. Sleeping for 70s to let schedules run"
|
||||||
# Schedules run on the shortest interval of a minute. This should allow time
|
# Schedules run on the shortest interval of a minute. This should allow time
|
||||||
# for the containers to start and execute once
|
# for the containers to start and execute once
|
||||||
local seconds=$((65 - $(date +"%S")))
|
sleep 70
|
||||||
echo "Containers started. Sleeping for ${seconds}s to let schedules run"
|
|
||||||
sleep $seconds
|
|
||||||
|
|
||||||
echo "Stopping containers"
|
echo "Stopping containers"
|
||||||
docker compose stop
|
docker-compose stop
|
||||||
|
|
||||||
# Print logs
|
|
||||||
docker compose logs
|
|
||||||
|
|
||||||
# Validate result shows minimum amount of executions
|
# Validate result shows minimum amount of executions
|
||||||
check_results ./start_result.txt 2
|
check_results ./start_result.txt 2
|
||||||
check_results ./exec_result.txt 1
|
check_results ./exec_result.txt 1
|
||||||
|
|
||||||
# Check for exec output
|
|
||||||
if ! (docker compose logs | grep -q "Yay!"); then
|
|
||||||
echo "Exec output 'Yay!' not found"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main
|
main
|
||||||
|
131
main.go
131
main.go
@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
@ -9,10 +8,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.iamthefij.com/iamthefij/slog"
|
|
||||||
dockerTypes "github.com/docker/docker/api/types"
|
dockerTypes "github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/container"
|
|
||||||
dockerClient "github.com/docker/docker/client"
|
dockerClient "github.com/docker/docker/client"
|
||||||
|
"github.com/iamthefij/dockron/slog"
|
||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
@ -30,15 +28,14 @@ var (
|
|||||||
version = "dev"
|
version = "dev"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerClient provides an interface for interracting with Docker. Makes it possible to mock in tests
|
// ContainerClient provides an interface for interracting with Docker
|
||||||
type ContainerClient interface {
|
type ContainerClient interface {
|
||||||
ContainerExecCreate(ctx context.Context, container string, config container.ExecOptions) (dockerTypes.IDResponse, error)
|
ContainerExecCreate(ctx context.Context, container string, config dockerTypes.ExecConfig) (dockerTypes.IDResponse, error)
|
||||||
ContainerExecInspect(ctx context.Context, execID string) (container.ExecInspect, error)
|
ContainerExecInspect(ctx context.Context, execID string) (dockerTypes.ContainerExecInspect, error)
|
||||||
ContainerExecStart(ctx context.Context, execID string, config container.ExecStartOptions) error
|
ContainerExecStart(ctx context.Context, execID string, config dockerTypes.ExecStartCheck) error
|
||||||
ContainerExecAttach(ctx context.Context, execID string, options container.ExecAttachOptions) (dockerTypes.HijackedResponse, error)
|
|
||||||
ContainerInspect(ctx context.Context, containerID string) (dockerTypes.ContainerJSON, error)
|
ContainerInspect(ctx context.Context, containerID string) (dockerTypes.ContainerJSON, error)
|
||||||
ContainerList(context context.Context, options container.ListOptions) ([]dockerTypes.Container, error)
|
ContainerList(context context.Context, options dockerTypes.ContainerListOptions) ([]dockerTypes.Container, error)
|
||||||
ContainerStart(context context.Context, containerID string, options container.StartOptions) error
|
ContainerStart(context context.Context, containerID string, options dockerTypes.ContainerStartOptions) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainerCronJob is an interface of a job to run on containers
|
// ContainerCronJob is an interface of a job to run on containers
|
||||||
@ -63,18 +60,17 @@ type ContainerStartJob struct {
|
|||||||
// Run is executed based on the ContainerStartJob Schedule and starts the
|
// Run is executed based on the ContainerStartJob Schedule and starts the
|
||||||
// container
|
// container
|
||||||
func (job ContainerStartJob) Run() {
|
func (job ContainerStartJob) Run() {
|
||||||
slog.Infof("Starting: %s", job.name)
|
slog.Info("Starting: %s", job.name)
|
||||||
|
|
||||||
// Check if container is already running
|
// Check if container is already running
|
||||||
containerJSON, err := job.client.ContainerInspect(
|
containerJSON, err := job.client.ContainerInspect(
|
||||||
job.context,
|
job.context,
|
||||||
job.containerID,
|
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 {
|
if containerJSON.State.Running {
|
||||||
slog.Warningf("%s: Container is already running. Skipping start.", job.name)
|
slog.Warning("Container is already running. Skipping %s", job.name)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,32 +78,32 @@ func (job ContainerStartJob) Run() {
|
|||||||
err = job.client.ContainerStart(
|
err = job.client.ContainerStart(
|
||||||
job.context,
|
job.context,
|
||||||
job.containerID,
|
job.containerID,
|
||||||
container.StartOptions{},
|
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
|
// Check results of job
|
||||||
for check := true; check; check = containerJSON.State.Running {
|
for check := true; check; check = containerJSON.State.Running {
|
||||||
slog.Debugf("%s: Still running", job.name)
|
slog.Debug("Still running %s", job.name)
|
||||||
|
|
||||||
containerJSON, err = job.client.ContainerInspect(
|
containerJSON, err = job.client.ContainerInspect(
|
||||||
job.context,
|
job.context,
|
||||||
job.containerID,
|
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)
|
time.Sleep(1 * time.Second)
|
||||||
}
|
}
|
||||||
slog.Debugf("%s: Done running. %+v", job.name, containerJSON.State)
|
slog.Debug("Done execing %s. %+v", job.name, containerJSON.State)
|
||||||
|
|
||||||
// Log exit code if failed
|
// Log exit code if failed
|
||||||
if containerJSON.State.ExitCode != 0 {
|
if containerJSON.State.ExitCode != 0 {
|
||||||
slog.Errorf(
|
slog.Error(
|
||||||
"%s: Exec job exited with code %d",
|
"Exec job %s existed with code %d",
|
||||||
job.name,
|
job.name,
|
||||||
containerJSON.State.ExitCode,
|
containerJSON.State.ExitCode,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name returns the name of the job
|
// Name returns the name of the job
|
||||||
@ -136,104 +132,72 @@ type ContainerExecJob struct {
|
|||||||
// Run is executed based on the ContainerStartJob Schedule and starts the
|
// Run is executed based on the ContainerStartJob Schedule and starts the
|
||||||
// container
|
// container
|
||||||
func (job ContainerExecJob) Run() {
|
func (job ContainerExecJob) Run() {
|
||||||
slog.Infof("Execing: %s", job.name)
|
slog.Info("Execing: %s", job.name)
|
||||||
containerJSON, err := job.client.ContainerInspect(
|
containerJSON, err := job.client.ContainerInspect(
|
||||||
job.context,
|
job.context,
|
||||||
job.containerID,
|
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 {
|
if !containerJSON.State.Running {
|
||||||
slog.Warningf("%s: Container not running. Skipping exec.", job.name)
|
slog.Warning("Container not running. Skipping %s", job.name)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
execID, err := job.client.ContainerExecCreate(
|
execID, err := job.client.ContainerExecCreate(
|
||||||
job.context,
|
job.context,
|
||||||
job.containerID,
|
job.containerID,
|
||||||
container.ExecOptions{
|
dockerTypes.ExecConfig{
|
||||||
AttachStdout: true,
|
|
||||||
AttachStderr: true,
|
|
||||||
Cmd: []string{"sh", "-c", strings.TrimSpace(job.shellCommand)},
|
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)
|
||||||
|
|
||||||
hj, err := job.client.ContainerExecAttach(job.context, execID.ID, container.ExecAttachOptions{})
|
|
||||||
slog.OnErrWarnf(err, "%s: Error attaching to exec: %s", job.name, err)
|
|
||||||
defer hj.Close()
|
|
||||||
|
|
||||||
scanner := bufio.NewScanner(hj.Reader)
|
|
||||||
|
|
||||||
err = job.client.ContainerExecStart(
|
err = job.client.ContainerExecStart(
|
||||||
job.context,
|
job.context,
|
||||||
execID.ID,
|
execID.ID,
|
||||||
container.ExecStartOptions{},
|
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
|
// Wait for job results
|
||||||
execInfo := container.ExecInspect{Running: true}
|
execInfo := dockerTypes.ContainerExecInspect{Running: true}
|
||||||
for execInfo.Running {
|
for execInfo.Running {
|
||||||
time.Sleep(1 * time.Second)
|
slog.Debug("Still execing %s", job.name)
|
||||||
|
|
||||||
slog.Debugf("Still execing %s", job.name)
|
|
||||||
execInfo, err = job.client.ContainerExecInspect(
|
execInfo, err = job.client.ContainerExecInspect(
|
||||||
job.context,
|
job.context,
|
||||||
execID.ID,
|
execID.ID,
|
||||||
)
|
)
|
||||||
|
slog.Debug("Exec info: %+v", execInfo)
|
||||||
// Maybe print output
|
|
||||||
if hj.Reader != nil {
|
|
||||||
for scanner.Scan() {
|
|
||||||
line := scanner.Text()
|
|
||||||
if len(line) > 0 {
|
|
||||||
slog.Infof("%s: Exec output: %s", job.name, line)
|
|
||||||
} else {
|
|
||||||
slog.Debugf("%s: Empty exec output", job.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := scanner.Err(); err != nil {
|
|
||||||
slog.OnErrWarnf(err, "%s: Error reading from exec", job.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
slog.Debugf("%s: No exec reader", job.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
slog.Debugf("%s: Exec info: %+v", job.name, execInfo)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Nothing we can do if we got an error here, so let's go
|
// Nothing we can do if we got an error here, so let's go
|
||||||
slog.OnErrWarnf(err, "%s: Could not get status for exec job", job.name)
|
slog.WarnOnErr(err, "Could not get status for exec job %s", job.name)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
}
|
}
|
||||||
slog.Debugf("%s: Done execing. %+v", job.name, execInfo)
|
slog.Debug("Done execing %s. %+v", job.name, execInfo)
|
||||||
// Log exit code if failed
|
// Log exit code if failed
|
||||||
if execInfo.ExitCode != 0 {
|
if execInfo.ExitCode != 0 {
|
||||||
slog.Errorf("%s: Exec job 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
|
// QueryScheduledJobs queries Docker for all containers with a schedule and
|
||||||
// returns a list of ContainerCronJob records to be scheduled
|
// returns a list of ContainerCronJob records to be scheduled
|
||||||
func QueryScheduledJobs(client ContainerClient) (jobs []ContainerCronJob) {
|
func QueryScheduledJobs(client ContainerClient) (jobs []ContainerCronJob) {
|
||||||
slog.Debugf("Scanning containers for new schedules...")
|
slog.Debug("Scanning containers for new schedules...")
|
||||||
|
|
||||||
containers, err := client.ContainerList(
|
containers, err := client.ContainerList(
|
||||||
context.Background(),
|
context.Background(),
|
||||||
container.ListOptions{All: true},
|
dockerTypes.ContainerListOptions{All: true},
|
||||||
)
|
)
|
||||||
slog.OnErrPanicf(err, "Failure querying docker containers")
|
slog.PanicOnErr(err, "Failure querying docker containers")
|
||||||
|
|
||||||
for _, container := range containers {
|
for _, container := range containers {
|
||||||
// Add start job
|
// Add start job
|
||||||
if val, ok := container.Labels[schedLabel]; ok {
|
if val, ok := container.Labels[schedLabel]; ok {
|
||||||
jobName := strings.Join(container.Names, "/")
|
jobName := strings.Join(container.Names, "/")
|
||||||
|
|
||||||
jobs = append(jobs, ContainerStartJob{
|
jobs = append(jobs, ContainerStartJob{
|
||||||
client: client,
|
client: client,
|
||||||
containerID: container.ID,
|
containerID: container.ID,
|
||||||
@ -245,12 +209,9 @@ func QueryScheduledJobs(client ContainerClient) (jobs []ContainerCronJob) {
|
|||||||
|
|
||||||
// Add exec jobs
|
// Add exec jobs
|
||||||
execJobs := map[string]map[string]string{}
|
execJobs := map[string]map[string]string{}
|
||||||
|
|
||||||
for label, value := range container.Labels {
|
for label, value := range container.Labels {
|
||||||
results := execLabelRegexp.FindStringSubmatch(label)
|
results := execLabelRegexp.FindStringSubmatch(label)
|
||||||
expectedLabelParts := 3
|
if len(results) == 3 {
|
||||||
|
|
||||||
if len(results) == expectedLabelParts {
|
|
||||||
// We've got part of a new job
|
// We've got part of a new job
|
||||||
jobName, jobField := results[1], results[2]
|
jobName, jobField := results[1], results[2]
|
||||||
if partJob, ok := execJobs[jobName]; ok {
|
if partJob, ok := execJobs[jobName]; ok {
|
||||||
@ -264,18 +225,15 @@ func QueryScheduledJobs(client ContainerClient) (jobs []ContainerCronJob) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for jobName, jobConfig := range execJobs {
|
for jobName, jobConfig := range execJobs {
|
||||||
schedule, ok := jobConfig["schedule"]
|
schedule, ok := jobConfig["schedule"]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
shellCommand, ok := jobConfig["command"]
|
shellCommand, ok := jobConfig["command"]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
jobs = append(jobs, ContainerExecJob{
|
jobs = append(jobs, ContainerExecJob{
|
||||||
ContainerStartJob: ContainerStartJob{
|
ContainerStartJob: ContainerStartJob{
|
||||||
client: client,
|
client: client,
|
||||||
@ -289,7 +247,7 @@ func QueryScheduledJobs(client ContainerClient) (jobs []ContainerCronJob) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return jobs
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScheduleJobs accepts a Cron instance and a list of jobs to schedule.
|
// ScheduleJobs accepts a Cron instance and a list of jobs to schedule.
|
||||||
@ -306,16 +264,15 @@ func ScheduleJobs(c *cron.Cron, jobs []ContainerCronJob) {
|
|||||||
if _, ok := existingJobs[job.UniqueName()]; ok {
|
if _, ok := existingJobs[job.UniqueName()]; ok {
|
||||||
// Job already exists, remove it from existing jobs so we don't
|
// Job already exists, remove it from existing jobs so we don't
|
||||||
// unschedule it later
|
// 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())
|
delete(existingJobs, job.UniqueName())
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Job doesn't exist yet, schedule it
|
// Job doesn't exist yet, schedule it
|
||||||
_, err := c.AddJob(job.Schedule(), job)
|
_, err := c.AddJob(job.Schedule(), job)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
slog.Infof(
|
slog.Info(
|
||||||
"Scheduled %s (%s) with schedule '%s'\n",
|
"Scheduled %s (%s) with schedule '%s'\n",
|
||||||
job.Name(),
|
job.Name(),
|
||||||
job.UniqueName(),
|
job.UniqueName(),
|
||||||
@ -323,7 +280,7 @@ func ScheduleJobs(c *cron.Cron, jobs []ContainerCronJob) {
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// TODO: Track something for a healthcheck here
|
// TODO: Track something for a healthcheck here
|
||||||
slog.Errorf(
|
slog.Error(
|
||||||
"Could not schedule %s (%s) with schedule '%s'. %v\n",
|
"Could not schedule %s (%s) with schedule '%s'. %v\n",
|
||||||
job.Name(),
|
job.Name(),
|
||||||
job.UniqueName(),
|
job.UniqueName(),
|
||||||
@ -342,14 +299,14 @@ func ScheduleJobs(c *cron.Cron, jobs []ContainerCronJob) {
|
|||||||
func main() {
|
func main() {
|
||||||
// Get a Docker Client
|
// Get a Docker Client
|
||||||
client, err := dockerClient.NewClientWithOpts(dockerClient.FromEnv)
|
client, err := dockerClient.NewClientWithOpts(dockerClient.FromEnv)
|
||||||
slog.OnErrPanicf(err, "Could not create Docker client")
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Read interval for polling Docker
|
// Read interval for polling Docker
|
||||||
var watchInterval time.Duration
|
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")
|
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.BoolVar(&slog.DebugLevel, "debug", false, "Show debug logs")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
281
main_test.go
281
main_test.go
@ -1,17 +1,13 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
dockerTypes "github.com/docker/docker/api/types"
|
dockerTypes "github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/container"
|
|
||||||
"github.com/robfig/cron/v3"
|
"github.com/robfig/cron/v3"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
@ -33,8 +29,6 @@ var (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
errGeneric = errors.New("error")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// FakeCall represents a faked method call
|
// FakeCall represents a faked method call
|
||||||
@ -51,8 +45,6 @@ type FakeDockerClient struct {
|
|||||||
|
|
||||||
// AssertFakeCalls checks expected against actual calls to fake methods
|
// AssertFakeCalls checks expected against actual calls to fake methods
|
||||||
func (fakeClient FakeDockerClient) AssertFakeCalls(t *testing.T, expectedCalls map[string][]FakeCall, message string) {
|
func (fakeClient FakeDockerClient) AssertFakeCalls(t *testing.T, expectedCalls map[string][]FakeCall, message string) {
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(fakeClient.FakeCalls, expectedCalls) {
|
if !reflect.DeepEqual(fakeClient.FakeCalls, expectedCalls) {
|
||||||
t.Errorf(
|
t.Errorf(
|
||||||
"%s: Expected and actual calls do not match. Expected %+v Actual %+v",
|
"%s: Expected and actual calls do not match. Expected %+v Actual %+v",
|
||||||
@ -78,60 +70,52 @@ func (fakeClient *FakeDockerClient) called(method string, v ...interface{}) Fake
|
|||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fakeClient *FakeDockerClient) ContainerStart(context context.Context, containerID string, options container.StartOptions) (e error) {
|
func (fakeClient *FakeDockerClient) ContainerStart(context context.Context, containerID string, options dockerTypes.ContainerStartOptions) (e error) {
|
||||||
results := fakeClient.called("ContainerStart", context, containerID, options)
|
results := fakeClient.called("ContainerStart", context, containerID, options)
|
||||||
if results[0] != nil {
|
if results[0] != nil {
|
||||||
e = results[0].(error)
|
e = results[0].(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fakeClient *FakeDockerClient) ContainerList(context context.Context, options container.ListOptions) (c []dockerTypes.Container, e error) {
|
func (fakeClient *FakeDockerClient) ContainerList(context context.Context, options dockerTypes.ContainerListOptions) (c []dockerTypes.Container, e error) {
|
||||||
results := fakeClient.called("ContainerList", context, options)
|
results := fakeClient.called("ContainerList", context, options)
|
||||||
if results[0] != nil {
|
if results[0] != nil {
|
||||||
c = results[0].([]dockerTypes.Container)
|
c = results[0].([]dockerTypes.Container)
|
||||||
}
|
}
|
||||||
|
|
||||||
if results[1] != nil {
|
if results[1] != nil {
|
||||||
e = results[1].(error)
|
e = results[1].(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fakeClient *FakeDockerClient) ContainerExecCreate(ctx context.Context, container string, config container.ExecOptions) (r dockerTypes.IDResponse, e error) {
|
func (fakeClient *FakeDockerClient) ContainerExecCreate(ctx context.Context, container string, config dockerTypes.ExecConfig) (r dockerTypes.IDResponse, e error) {
|
||||||
results := fakeClient.called("ContainerExecCreate", ctx, container, config)
|
results := fakeClient.called("ContainerExecCreate", ctx, container, config)
|
||||||
if results[0] != nil {
|
if results[0] != nil {
|
||||||
r = results[0].(dockerTypes.IDResponse)
|
r = results[0].(dockerTypes.IDResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
if results[1] != nil {
|
if results[1] != nil {
|
||||||
e = results[1].(error)
|
e = results[1].(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fakeClient *FakeDockerClient) ContainerExecStart(ctx context.Context, execID string, config container.ExecStartOptions) (e error) {
|
func (fakeClient *FakeDockerClient) ContainerExecStart(ctx context.Context, execID string, config dockerTypes.ExecStartCheck) (e error) {
|
||||||
results := fakeClient.called("ContainerExecStart", ctx, execID, config)
|
results := fakeClient.called("ContainerExecStart", ctx, execID, config)
|
||||||
if results[0] != nil {
|
if results[0] != nil {
|
||||||
e = results[0].(error)
|
e = results[0].(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fakeClient *FakeDockerClient) ContainerExecInspect(ctx context.Context, execID string) (r container.ExecInspect, e error) {
|
func (fakeClient *FakeDockerClient) ContainerExecInspect(ctx context.Context, execID string) (r dockerTypes.ContainerExecInspect, e error) {
|
||||||
results := fakeClient.called("ContainerExecInspect", ctx, execID)
|
results := fakeClient.called("ContainerExecInspect", ctx, execID)
|
||||||
if results[0] != nil {
|
if results[0] != nil {
|
||||||
r = results[0].(container.ExecInspect)
|
r = results[0].(dockerTypes.ContainerExecInspect)
|
||||||
}
|
}
|
||||||
|
|
||||||
if results[1] != nil {
|
if results[1] != nil {
|
||||||
e = results[1].(error)
|
e = results[1].(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,20 +124,12 @@ func (fakeClient *FakeDockerClient) ContainerInspect(ctx context.Context, contai
|
|||||||
if results[0] != nil {
|
if results[0] != nil {
|
||||||
r = results[0].(dockerTypes.ContainerJSON)
|
r = results[0].(dockerTypes.ContainerJSON)
|
||||||
}
|
}
|
||||||
|
|
||||||
if results[1] != nil {
|
if results[1] != nil {
|
||||||
e = results[1].(error)
|
e = results[1].(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fakeClient *FakeDockerClient) ContainerExecAttach(ctx context.Context, execID string, options container.ExecAttachOptions) (dockerTypes.HijackedResponse, error) {
|
|
||||||
return dockerTypes.HijackedResponse{
|
|
||||||
Reader: bufio.NewReader(strings.NewReader("Some output from our command")),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFakeDockerClient creates an empty client
|
// NewFakeDockerClient creates an empty client
|
||||||
func NewFakeDockerClient() *FakeDockerClient {
|
func NewFakeDockerClient() *FakeDockerClient {
|
||||||
return &FakeDockerClient{
|
return &FakeDockerClient{
|
||||||
@ -163,8 +139,6 @@ func NewFakeDockerClient() *FakeDockerClient {
|
|||||||
|
|
||||||
// ErrorUnequal checks that two values are equal and fails the test if not
|
// ErrorUnequal checks that two values are equal and fails the test if not
|
||||||
func ErrorUnequal(t *testing.T, expected interface{}, actual interface{}, message string) {
|
func ErrorUnequal(t *testing.T, expected interface{}, actual interface{}, message string) {
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
if expected != actual {
|
if expected != actual {
|
||||||
t.Errorf("%s Expected: %+v Actual: %+v", message, expected, actual)
|
t.Errorf("%s Expected: %+v Actual: %+v", message, expected, actual)
|
||||||
}
|
}
|
||||||
@ -188,7 +162,7 @@ func TestQueryScheduledJobs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "One container without schedule",
|
name: "One container without schedule",
|
||||||
fakeContainers: []dockerTypes.Container{
|
fakeContainers: []dockerTypes.Container{
|
||||||
{
|
dockerTypes.Container{
|
||||||
Names: []string{"no_schedule_1"},
|
Names: []string{"no_schedule_1"},
|
||||||
ID: "no_schedule_1",
|
ID: "no_schedule_1",
|
||||||
},
|
},
|
||||||
@ -198,7 +172,7 @@ func TestQueryScheduledJobs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "One container with schedule",
|
name: "One container with schedule",
|
||||||
fakeContainers: []dockerTypes.Container{
|
fakeContainers: []dockerTypes.Container{
|
||||||
{
|
dockerTypes.Container{
|
||||||
Names: []string{"has_schedule_1"},
|
Names: []string{"has_schedule_1"},
|
||||||
ID: "has_schedule_1",
|
ID: "has_schedule_1",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
@ -219,11 +193,11 @@ func TestQueryScheduledJobs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "One container with and one without schedule",
|
name: "One container with and one without schedule",
|
||||||
fakeContainers: []dockerTypes.Container{
|
fakeContainers: []dockerTypes.Container{
|
||||||
{
|
dockerTypes.Container{
|
||||||
Names: []string{"no_schedule_1"},
|
Names: []string{"no_schedule_1"},
|
||||||
ID: "no_schedule_1",
|
ID: "no_schedule_1",
|
||||||
},
|
},
|
||||||
{
|
dockerTypes.Container{
|
||||||
Names: []string{"has_schedule_1"},
|
Names: []string{"has_schedule_1"},
|
||||||
ID: "has_schedule_1",
|
ID: "has_schedule_1",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
@ -244,7 +218,7 @@ func TestQueryScheduledJobs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "Incomplete exec job, schedule only",
|
name: "Incomplete exec job, schedule only",
|
||||||
fakeContainers: []dockerTypes.Container{
|
fakeContainers: []dockerTypes.Container{
|
||||||
{
|
dockerTypes.Container{
|
||||||
Names: []string{"exec_job_1"},
|
Names: []string{"exec_job_1"},
|
||||||
ID: "exec_job_1",
|
ID: "exec_job_1",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
@ -257,7 +231,7 @@ func TestQueryScheduledJobs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "Incomplete exec job, command only",
|
name: "Incomplete exec job, command only",
|
||||||
fakeContainers: []dockerTypes.Container{
|
fakeContainers: []dockerTypes.Container{
|
||||||
{
|
dockerTypes.Container{
|
||||||
Names: []string{"exec_job_1"},
|
Names: []string{"exec_job_1"},
|
||||||
ID: "exec_job_1",
|
ID: "exec_job_1",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
@ -270,7 +244,7 @@ func TestQueryScheduledJobs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "Complete exec job",
|
name: "Complete exec job",
|
||||||
fakeContainers: []dockerTypes.Container{
|
fakeContainers: []dockerTypes.Container{
|
||||||
{
|
dockerTypes.Container{
|
||||||
Names: []string{"exec_job_1"},
|
Names: []string{"exec_job_1"},
|
||||||
ID: "exec_job_1",
|
ID: "exec_job_1",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
@ -295,7 +269,7 @@ func TestQueryScheduledJobs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "Dual exec jobs on single container",
|
name: "Dual exec jobs on single container",
|
||||||
fakeContainers: []dockerTypes.Container{
|
fakeContainers: []dockerTypes.Container{
|
||||||
{
|
dockerTypes.Container{
|
||||||
Names: []string{"exec_job_1"},
|
Names: []string{"exec_job_1"},
|
||||||
ID: "exec_job_1",
|
ID: "exec_job_1",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
@ -338,7 +312,7 @@ func TestQueryScheduledJobs(t *testing.T) {
|
|||||||
// Load fake containers
|
// Load fake containers
|
||||||
t.Logf("Fake containers: %+v", c.fakeContainers)
|
t.Logf("Fake containers: %+v", c.fakeContainers)
|
||||||
client.FakeResults["ContainerList"] = []FakeResult{
|
client.FakeResults["ContainerList"] = []FakeResult{
|
||||||
{c.fakeContainers, nil},
|
FakeResult{c.fakeContainers, nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
jobs := QueryScheduledJobs(client)
|
jobs := QueryScheduledJobs(client)
|
||||||
@ -349,7 +323,6 @@ func TestQueryScheduledJobs(t *testing.T) {
|
|||||||
|
|
||||||
t.Logf("Expected jobs: %+v, Actual jobs: %+v", c.expectedJobs, jobs)
|
t.Logf("Expected jobs: %+v, Actual jobs: %+v", c.expectedJobs, jobs)
|
||||||
ErrorUnequal(t, len(c.expectedJobs), len(jobs), "Job lengths don't match")
|
ErrorUnequal(t, len(c.expectedJobs), len(jobs), "Job lengths don't match")
|
||||||
|
|
||||||
for i, job := range jobs {
|
for i, job := range jobs {
|
||||||
ErrorUnequal(t, c.expectedJobs[i], job, "Job value does not match")
|
ErrorUnequal(t, c.expectedJobs[i], job, "Job value does not match")
|
||||||
}
|
}
|
||||||
@ -458,7 +431,6 @@ func TestScheduleJobs(t *testing.T) {
|
|||||||
t.Logf("Cron entries: %+v", scheduledEntries)
|
t.Logf("Cron entries: %+v", scheduledEntries)
|
||||||
|
|
||||||
ErrorUnequal(t, len(c.expectedJobs), len(scheduledEntries), "Job and entry lengths don't match")
|
ErrorUnequal(t, len(c.expectedJobs), len(scheduledEntries), "Job and entry lengths don't match")
|
||||||
|
|
||||||
for i, entry := range scheduledEntries {
|
for i, entry := range scheduledEntries {
|
||||||
ErrorUnequal(t, c.expectedJobs[i], entry.Job, "Job value does not match entry")
|
ErrorUnequal(t, c.expectedJobs[i], entry.Job, "Job value does not match entry")
|
||||||
}
|
}
|
||||||
@ -487,7 +459,7 @@ func TestDoLoop(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "One container without schedule",
|
name: "One container without schedule",
|
||||||
fakeContainers: []dockerTypes.Container{
|
fakeContainers: []dockerTypes.Container{
|
||||||
{
|
dockerTypes.Container{
|
||||||
Names: []string{"no_schedule_1"},
|
Names: []string{"no_schedule_1"},
|
||||||
ID: "no_schedule_1",
|
ID: "no_schedule_1",
|
||||||
},
|
},
|
||||||
@ -497,7 +469,7 @@ func TestDoLoop(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "One container with schedule",
|
name: "One container with schedule",
|
||||||
fakeContainers: []dockerTypes.Container{
|
fakeContainers: []dockerTypes.Container{
|
||||||
{
|
dockerTypes.Container{
|
||||||
Names: []string{"has_schedule_1"},
|
Names: []string{"has_schedule_1"},
|
||||||
ID: "has_schedule_1",
|
ID: "has_schedule_1",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
@ -518,11 +490,11 @@ func TestDoLoop(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "One container with and one without schedule",
|
name: "One container with and one without schedule",
|
||||||
fakeContainers: []dockerTypes.Container{
|
fakeContainers: []dockerTypes.Container{
|
||||||
{
|
dockerTypes.Container{
|
||||||
Names: []string{"no_schedule_1"},
|
Names: []string{"no_schedule_1"},
|
||||||
ID: "no_schedule_1",
|
ID: "no_schedule_1",
|
||||||
},
|
},
|
||||||
{
|
dockerTypes.Container{
|
||||||
Names: []string{"has_schedule_1"},
|
Names: []string{"has_schedule_1"},
|
||||||
ID: "has_schedule_1",
|
ID: "has_schedule_1",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
@ -543,14 +515,14 @@ func TestDoLoop(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "Add a second container with a schedule",
|
name: "Add a second container with a schedule",
|
||||||
fakeContainers: []dockerTypes.Container{
|
fakeContainers: []dockerTypes.Container{
|
||||||
{
|
dockerTypes.Container{
|
||||||
Names: []string{"has_schedule_1"},
|
Names: []string{"has_schedule_1"},
|
||||||
ID: "has_schedule_1",
|
ID: "has_schedule_1",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"dockron.schedule": "* * * * *",
|
"dockron.schedule": "* * * * *",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
dockerTypes.Container{
|
||||||
Names: []string{"has_schedule_2"},
|
Names: []string{"has_schedule_2"},
|
||||||
ID: "has_schedule_2",
|
ID: "has_schedule_2",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
@ -578,14 +550,14 @@ func TestDoLoop(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "Modify the first container",
|
name: "Modify the first container",
|
||||||
fakeContainers: []dockerTypes.Container{
|
fakeContainers: []dockerTypes.Container{
|
||||||
{
|
dockerTypes.Container{
|
||||||
Names: []string{"has_schedule_1"},
|
Names: []string{"has_schedule_1"},
|
||||||
ID: "has_schedule_1_prime",
|
ID: "has_schedule_1_prime",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"dockron.schedule": "* * * * *",
|
"dockron.schedule": "* * * * *",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
dockerTypes.Container{
|
||||||
Names: []string{"has_schedule_2"},
|
Names: []string{"has_schedule_2"},
|
||||||
ID: "has_schedule_2",
|
ID: "has_schedule_2",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
@ -613,7 +585,7 @@ func TestDoLoop(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "Remove second container and add exec to first",
|
name: "Remove second container and add exec to first",
|
||||||
fakeContainers: []dockerTypes.Container{
|
fakeContainers: []dockerTypes.Container{
|
||||||
{
|
dockerTypes.Container{
|
||||||
Names: []string{"has_schedule_1"},
|
Names: []string{"has_schedule_1"},
|
||||||
ID: "has_schedule_1_prime",
|
ID: "has_schedule_1_prime",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
@ -652,7 +624,7 @@ func TestDoLoop(t *testing.T) {
|
|||||||
// Load fake containers
|
// Load fake containers
|
||||||
t.Logf("Fake containers: %+v", c.fakeContainers)
|
t.Logf("Fake containers: %+v", c.fakeContainers)
|
||||||
client.FakeResults["ContainerList"] = []FakeResult{
|
client.FakeResults["ContainerList"] = []FakeResult{
|
||||||
{c.fakeContainers, nil},
|
FakeResult{c.fakeContainers, nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute loop iteration loop
|
// Execute loop iteration loop
|
||||||
@ -665,7 +637,6 @@ func TestDoLoop(t *testing.T) {
|
|||||||
t.Logf("Cron entries: %+v", scheduledEntries)
|
t.Logf("Cron entries: %+v", scheduledEntries)
|
||||||
|
|
||||||
ErrorUnequal(t, len(c.expectedJobs), len(scheduledEntries), "Job and entry lengths don't match")
|
ErrorUnequal(t, len(c.expectedJobs), len(scheduledEntries), "Job and entry lengths don't match")
|
||||||
|
|
||||||
for i, entry := range scheduledEntries {
|
for i, entry := range scheduledEntries {
|
||||||
ErrorUnequal(t, c.expectedJobs[i], entry.Job, "Job value does not match entry")
|
ErrorUnequal(t, c.expectedJobs[i], entry.Job, "Job value does not match entry")
|
||||||
}
|
}
|
||||||
@ -682,8 +653,8 @@ func TestDoLoop(t *testing.T) {
|
|||||||
// to a subpackage that offers a single function for interfacing with the
|
// 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.
|
// Docker client to start or exec a container so that Dockron needn't care.
|
||||||
func TestRunExecJobs(t *testing.T) {
|
func TestRunExecJobs(t *testing.T) {
|
||||||
var jobContext context.Context
|
|
||||||
|
|
||||||
|
var jobContext context.Context
|
||||||
jobContainerID := "container_id"
|
jobContainerID := "container_id"
|
||||||
jobCommand := "true"
|
jobCommand := "true"
|
||||||
|
|
||||||
@ -697,13 +668,13 @@ func TestRunExecJobs(t *testing.T) {
|
|||||||
name: "Initial inspect call raises error",
|
name: "Initial inspect call raises error",
|
||||||
client: &FakeDockerClient{
|
client: &FakeDockerClient{
|
||||||
FakeResults: map[string][]FakeResult{
|
FakeResults: map[string][]FakeResult{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeResult{
|
||||||
{nil, errGeneric},
|
FakeResult{nil, fmt.Errorf("error")},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedCalls: map[string][]FakeCall{
|
expectedCalls: map[string][]FakeCall{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeCall{
|
||||||
FakeCall{jobContext, jobContainerID},
|
FakeCall{jobContext, jobContainerID},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -713,14 +684,14 @@ func TestRunExecJobs(t *testing.T) {
|
|||||||
name: "Handle container not running",
|
name: "Handle container not running",
|
||||||
client: &FakeDockerClient{
|
client: &FakeDockerClient{
|
||||||
FakeResults: map[string][]FakeResult{
|
FakeResults: map[string][]FakeResult{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeResult{
|
||||||
{stoppedContainerInfo, nil},
|
FakeResult{stoppedContainerInfo, nil},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedCalls: map[string][]FakeCall{
|
expectedCalls: map[string][]FakeCall{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeCall{
|
||||||
{jobContext, jobContainerID},
|
FakeCall{jobContext, jobContainerID},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -728,25 +699,23 @@ func TestRunExecJobs(t *testing.T) {
|
|||||||
name: "Handle error creating exec",
|
name: "Handle error creating exec",
|
||||||
client: &FakeDockerClient{
|
client: &FakeDockerClient{
|
||||||
FakeResults: map[string][]FakeResult{
|
FakeResults: map[string][]FakeResult{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeResult{
|
||||||
{runningContainerInfo, nil},
|
FakeResult{runningContainerInfo, nil},
|
||||||
},
|
},
|
||||||
"ContainerExecCreate": {
|
"ContainerExecCreate": []FakeResult{
|
||||||
{nil, errGeneric},
|
FakeResult{nil, fmt.Errorf("fail")},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedCalls: map[string][]FakeCall{
|
expectedCalls: map[string][]FakeCall{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeCall{
|
||||||
{jobContext, jobContainerID},
|
FakeCall{jobContext, jobContainerID},
|
||||||
},
|
},
|
||||||
"ContainerExecCreate": {
|
"ContainerExecCreate": []FakeCall{
|
||||||
{
|
FakeCall{
|
||||||
jobContext,
|
jobContext,
|
||||||
jobContainerID,
|
jobContainerID,
|
||||||
container.ExecOptions{
|
dockerTypes.ExecConfig{
|
||||||
AttachStdout: true,
|
|
||||||
AttachStderr: true,
|
|
||||||
Cmd: []string{"sh", "-c", jobCommand},
|
Cmd: []string{"sh", "-c", jobCommand},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -758,34 +727,32 @@ func TestRunExecJobs(t *testing.T) {
|
|||||||
name: "Fail starting exec container",
|
name: "Fail starting exec container",
|
||||||
client: &FakeDockerClient{
|
client: &FakeDockerClient{
|
||||||
FakeResults: map[string][]FakeResult{
|
FakeResults: map[string][]FakeResult{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeResult{
|
||||||
{runningContainerInfo, nil},
|
FakeResult{runningContainerInfo, nil},
|
||||||
},
|
},
|
||||||
"ContainerExecCreate": {
|
"ContainerExecCreate": []FakeResult{
|
||||||
{dockerTypes.IDResponse{ID: "id"}, nil},
|
FakeResult{dockerTypes.IDResponse{ID: "id"}, nil},
|
||||||
},
|
},
|
||||||
"ContainerExecStart": {
|
"ContainerExecStart": []FakeResult{
|
||||||
{errGeneric},
|
FakeResult{fmt.Errorf("fail")},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedCalls: map[string][]FakeCall{
|
expectedCalls: map[string][]FakeCall{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeCall{
|
||||||
{jobContext, jobContainerID},
|
FakeCall{jobContext, jobContainerID},
|
||||||
},
|
},
|
||||||
"ContainerExecCreate": {
|
"ContainerExecCreate": []FakeCall{
|
||||||
{
|
FakeCall{
|
||||||
jobContext,
|
jobContext,
|
||||||
jobContainerID,
|
jobContainerID,
|
||||||
container.ExecOptions{
|
dockerTypes.ExecConfig{
|
||||||
AttachStdout: true,
|
|
||||||
AttachStderr: true,
|
|
||||||
Cmd: []string{"sh", "-c", jobCommand},
|
Cmd: []string{"sh", "-c", jobCommand},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"ContainerExecStart": {
|
"ContainerExecStart": []FakeCall{
|
||||||
{jobContext, "id", container.ExecStartOptions{}},
|
FakeCall{jobContext, "id", dockerTypes.ExecStartCheck{}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectPanic: true,
|
expectPanic: true,
|
||||||
@ -794,40 +761,38 @@ func TestRunExecJobs(t *testing.T) {
|
|||||||
name: "Successfully start an exec job fail on status",
|
name: "Successfully start an exec job fail on status",
|
||||||
client: &FakeDockerClient{
|
client: &FakeDockerClient{
|
||||||
FakeResults: map[string][]FakeResult{
|
FakeResults: map[string][]FakeResult{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeResult{
|
||||||
{runningContainerInfo, nil},
|
FakeResult{runningContainerInfo, nil},
|
||||||
},
|
},
|
||||||
"ContainerExecCreate": {
|
"ContainerExecCreate": []FakeResult{
|
||||||
{dockerTypes.IDResponse{ID: "id"}, nil},
|
FakeResult{dockerTypes.IDResponse{ID: "id"}, nil},
|
||||||
},
|
},
|
||||||
"ContainerExecStart": {
|
"ContainerExecStart": []FakeResult{
|
||||||
{nil},
|
FakeResult{nil},
|
||||||
},
|
},
|
||||||
"ContainerExecInspect": {
|
"ContainerExecInspect": []FakeResult{
|
||||||
{nil, errGeneric},
|
FakeResult{nil, fmt.Errorf("fail")},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedCalls: map[string][]FakeCall{
|
expectedCalls: map[string][]FakeCall{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeCall{
|
||||||
{jobContext, jobContainerID},
|
FakeCall{jobContext, jobContainerID},
|
||||||
},
|
},
|
||||||
"ContainerExecCreate": {
|
"ContainerExecCreate": []FakeCall{
|
||||||
{
|
FakeCall{
|
||||||
jobContext,
|
jobContext,
|
||||||
jobContainerID,
|
jobContainerID,
|
||||||
container.ExecOptions{
|
dockerTypes.ExecConfig{
|
||||||
AttachStdout: true,
|
|
||||||
AttachStderr: true,
|
|
||||||
Cmd: []string{"sh", "-c", jobCommand},
|
Cmd: []string{"sh", "-c", jobCommand},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"ContainerExecStart": {
|
"ContainerExecStart": []FakeCall{
|
||||||
{jobContext, "id", container.ExecStartOptions{}},
|
FakeCall{jobContext, "id", dockerTypes.ExecStartCheck{}},
|
||||||
},
|
},
|
||||||
"ContainerExecInspect": {
|
"ContainerExecInspect": []FakeCall{
|
||||||
{jobContext, "id"},
|
FakeCall{jobContext, "id"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -835,42 +800,40 @@ func TestRunExecJobs(t *testing.T) {
|
|||||||
name: "Successfully start an exec job and run to completion",
|
name: "Successfully start an exec job and run to completion",
|
||||||
client: &FakeDockerClient{
|
client: &FakeDockerClient{
|
||||||
FakeResults: map[string][]FakeResult{
|
FakeResults: map[string][]FakeResult{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeResult{
|
||||||
{runningContainerInfo, nil},
|
FakeResult{runningContainerInfo, nil},
|
||||||
},
|
},
|
||||||
"ContainerExecCreate": {
|
"ContainerExecCreate": []FakeResult{
|
||||||
{dockerTypes.IDResponse{ID: "id"}, nil},
|
FakeResult{dockerTypes.IDResponse{ID: "id"}, nil},
|
||||||
},
|
},
|
||||||
"ContainerExecStart": {
|
"ContainerExecStart": []FakeResult{
|
||||||
{nil},
|
FakeResult{nil},
|
||||||
},
|
},
|
||||||
"ContainerExecInspect": {
|
"ContainerExecInspect": []FakeResult{
|
||||||
{container.ExecInspect{Running: true}, nil},
|
FakeResult{dockerTypes.ContainerExecInspect{Running: true}, nil},
|
||||||
{container.ExecInspect{Running: false}, nil},
|
FakeResult{dockerTypes.ContainerExecInspect{Running: false}, nil},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedCalls: map[string][]FakeCall{
|
expectedCalls: map[string][]FakeCall{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeCall{
|
||||||
{jobContext, jobContainerID},
|
FakeCall{jobContext, jobContainerID},
|
||||||
},
|
},
|
||||||
"ContainerExecCreate": {
|
"ContainerExecCreate": []FakeCall{
|
||||||
{
|
FakeCall{
|
||||||
jobContext,
|
jobContext,
|
||||||
jobContainerID,
|
jobContainerID,
|
||||||
container.ExecOptions{
|
dockerTypes.ExecConfig{
|
||||||
AttachStdout: true,
|
|
||||||
AttachStderr: true,
|
|
||||||
Cmd: []string{"sh", "-c", jobCommand},
|
Cmd: []string{"sh", "-c", jobCommand},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"ContainerExecStart": {
|
"ContainerExecStart": []FakeCall{
|
||||||
{jobContext, "id", container.ExecStartOptions{}},
|
FakeCall{jobContext, "id", dockerTypes.ExecStartCheck{}},
|
||||||
},
|
},
|
||||||
"ContainerExecInspect": {
|
"ContainerExecInspect": []FakeCall{
|
||||||
{jobContext, "id"},
|
FakeCall{jobContext, "id"},
|
||||||
{jobContext, "id"},
|
FakeCall{jobContext, "id"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -897,11 +860,9 @@ func TestRunExecJobs(t *testing.T) {
|
|||||||
t.Log("Recovered from panic")
|
t.Log("Recovered from panic")
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.client.AssertFakeCalls(t, c.expectedCalls, "Failed")
|
c.client.AssertFakeCalls(t, c.expectedCalls, "Failed")
|
||||||
}()
|
}()
|
||||||
job.Run()
|
job.Run()
|
||||||
|
|
||||||
if c.expectPanic {
|
if c.expectPanic {
|
||||||
t.Errorf("Expected panic but got none")
|
t.Errorf("Expected panic but got none")
|
||||||
}
|
}
|
||||||
@ -916,7 +877,6 @@ func TestRunExecJobs(t *testing.T) {
|
|||||||
// Docker client to start or exec a container so that Dockron needn't care.
|
// Docker client to start or exec a container so that Dockron needn't care.
|
||||||
func TestRunStartJobs(t *testing.T) {
|
func TestRunStartJobs(t *testing.T) {
|
||||||
var jobContext context.Context
|
var jobContext context.Context
|
||||||
|
|
||||||
jobContainerID := "container_id"
|
jobContainerID := "container_id"
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
@ -929,14 +889,14 @@ func TestRunStartJobs(t *testing.T) {
|
|||||||
name: "Initial inspect call raises error",
|
name: "Initial inspect call raises error",
|
||||||
client: &FakeDockerClient{
|
client: &FakeDockerClient{
|
||||||
FakeResults: map[string][]FakeResult{
|
FakeResults: map[string][]FakeResult{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeResult{
|
||||||
{nil, errGeneric},
|
FakeResult{nil, fmt.Errorf("error")},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedCalls: map[string][]FakeCall{
|
expectedCalls: map[string][]FakeCall{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeCall{
|
||||||
{jobContext, jobContainerID},
|
FakeCall{jobContext, jobContainerID},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectPanic: true,
|
expectPanic: true,
|
||||||
@ -945,14 +905,14 @@ func TestRunStartJobs(t *testing.T) {
|
|||||||
name: "Handle container already running",
|
name: "Handle container already running",
|
||||||
client: &FakeDockerClient{
|
client: &FakeDockerClient{
|
||||||
FakeResults: map[string][]FakeResult{
|
FakeResults: map[string][]FakeResult{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeResult{
|
||||||
{runningContainerInfo, nil},
|
FakeResult{runningContainerInfo, nil},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedCalls: map[string][]FakeCall{
|
expectedCalls: map[string][]FakeCall{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeCall{
|
||||||
{jobContext, jobContainerID},
|
FakeCall{jobContext, jobContainerID},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -960,41 +920,41 @@ func TestRunStartJobs(t *testing.T) {
|
|||||||
name: "Handle error starting container",
|
name: "Handle error starting container",
|
||||||
client: &FakeDockerClient{
|
client: &FakeDockerClient{
|
||||||
FakeResults: map[string][]FakeResult{
|
FakeResults: map[string][]FakeResult{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeResult{
|
||||||
{stoppedContainerInfo, nil},
|
FakeResult{stoppedContainerInfo, nil},
|
||||||
},
|
},
|
||||||
"ContainerStart": {{errGeneric}},
|
"ContainerStart": []FakeResult{FakeResult{fmt.Errorf("fail")}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedCalls: map[string][]FakeCall{
|
expectedCalls: map[string][]FakeCall{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeCall{
|
||||||
{jobContext, jobContainerID},
|
FakeCall{jobContext, jobContainerID},
|
||||||
},
|
},
|
||||||
"ContainerStart": {
|
"ContainerStart": []FakeCall{
|
||||||
{jobContext, jobContainerID, container.StartOptions{}},
|
FakeCall{jobContext, jobContainerID, dockerTypes.ContainerStartOptions{}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Successfully start a container",
|
name: "Succesfully start a container",
|
||||||
client: &FakeDockerClient{
|
client: &FakeDockerClient{
|
||||||
FakeResults: map[string][]FakeResult{
|
FakeResults: map[string][]FakeResult{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeResult{
|
||||||
{stoppedContainerInfo, nil},
|
FakeResult{stoppedContainerInfo, nil},
|
||||||
{runningContainerInfo, nil},
|
FakeResult{runningContainerInfo, nil},
|
||||||
{stoppedContainerInfo, nil},
|
FakeResult{stoppedContainerInfo, nil},
|
||||||
},
|
},
|
||||||
"ContainerStart": {{nil}},
|
"ContainerStart": []FakeResult{FakeResult{nil}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedCalls: map[string][]FakeCall{
|
expectedCalls: map[string][]FakeCall{
|
||||||
"ContainerInspect": {
|
"ContainerInspect": []FakeCall{
|
||||||
{jobContext, jobContainerID},
|
FakeCall{jobContext, jobContainerID},
|
||||||
{jobContext, jobContainerID},
|
FakeCall{jobContext, jobContainerID},
|
||||||
{jobContext, jobContainerID},
|
FakeCall{jobContext, jobContainerID},
|
||||||
},
|
},
|
||||||
"ContainerStart": {
|
"ContainerStart": []FakeCall{
|
||||||
{jobContext, jobContainerID, container.StartOptions{}},
|
FakeCall{jobContext, jobContainerID, dockerTypes.ContainerStartOptions{}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1014,15 +974,14 @@ func TestRunStartJobs(t *testing.T) {
|
|||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// Recover from panics, if there were any
|
// Recover from panics, if there were any
|
||||||
_ = recover()
|
recover()
|
||||||
|
|
||||||
c.client.AssertFakeCalls(t, c.expectedCalls, "Failed")
|
c.client.AssertFakeCalls(t, c.expectedCalls, "Failed")
|
||||||
}()
|
}()
|
||||||
job.Run()
|
job.Run()
|
||||||
|
|
||||||
if c.expectPanic {
|
if c.expectPanic {
|
||||||
t.Errorf("Expected panic but got none")
|
t.Errorf("Expected panic but got none")
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
54
slog/Readme.md
Normal file
54
slog/Readme.md
Normal 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
8
slog/add-docs-to-readme.sh
Executable 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
90
slog/slog.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user