MVP
This commit is contained in:
parent
248318571f
commit
11bd001494
15 changed files with 634 additions and 37 deletions
60
.github/workflows/go.yml
vendored
Normal file
60
.github/workflows/go.yml
vendored
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
name: Go
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v3
|
||||||
|
with:
|
||||||
|
go-version: '^1.18'
|
||||||
|
id: go
|
||||||
|
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
lfs: true
|
||||||
|
|
||||||
|
- name: golangci-lint
|
||||||
|
uses: golangci/golangci-lint-action@v3
|
||||||
|
with:
|
||||||
|
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
|
||||||
|
version: latest
|
||||||
|
|
||||||
|
# Optional: working directory, useful for monorepos
|
||||||
|
# working-directory: somedir
|
||||||
|
|
||||||
|
# Optional: golangci-lint command line arguments.
|
||||||
|
# args: --issues-exit-code=0
|
||||||
|
|
||||||
|
# Optional: show only new issues if it's a pull request. The default value is `false`.
|
||||||
|
# only-new-issues: true
|
||||||
|
|
||||||
|
# Optional: if set to true then the action will use pre-installed Go.
|
||||||
|
# skip-go-installation: true
|
||||||
|
|
||||||
|
# Optional: if set to true then the action don't cache or restore ~/go/pkg.
|
||||||
|
# skip-pkg-cache: true
|
||||||
|
|
||||||
|
# Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
|
||||||
|
# skip-build-cache: true
|
||||||
|
|
||||||
|
- name: Run GoReleaser
|
||||||
|
uses: goreleaser/goreleaser-action@v2
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
args: release --rm-dist
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -15,3 +15,4 @@
|
||||||
# vendor/
|
# vendor/
|
||||||
|
|
||||||
.idea/
|
.idea/
|
||||||
|
dist/
|
||||||
|
|
147
.golangci.yml
Normal file
147
.golangci.yml
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
linters-settings:
|
||||||
|
dupl:
|
||||||
|
threshold: 100
|
||||||
|
funlen:
|
||||||
|
lines: 100
|
||||||
|
statements: 50
|
||||||
|
gci:
|
||||||
|
local-prefixes: github.com/baez90/kreaper
|
||||||
|
goconst:
|
||||||
|
min-len: 2
|
||||||
|
min-occurrences: 2
|
||||||
|
gocritic:
|
||||||
|
enabled-tags:
|
||||||
|
- diagnostic
|
||||||
|
- opinionated
|
||||||
|
- performance
|
||||||
|
disabled-checks:
|
||||||
|
- ifElseChain
|
||||||
|
- octalLiteral
|
||||||
|
- wrapperFunc
|
||||||
|
# see https://github.com/golangci/golangci-lint/issues/2649
|
||||||
|
- hugeParam
|
||||||
|
- rangeValCopy
|
||||||
|
# settings:
|
||||||
|
# hugeParam:
|
||||||
|
# sizeThreshold: 200
|
||||||
|
|
||||||
|
gocyclo:
|
||||||
|
min-complexity: 15
|
||||||
|
goimports:
|
||||||
|
local-prefixes: github.com/baez90/kreaper
|
||||||
|
golint:
|
||||||
|
min-confidence: 0
|
||||||
|
gomnd:
|
||||||
|
settings:
|
||||||
|
mnd:
|
||||||
|
# don't include the "operation" and "assign"
|
||||||
|
checks:
|
||||||
|
- argument
|
||||||
|
- case
|
||||||
|
- condition
|
||||||
|
- return
|
||||||
|
gomoddirectives:
|
||||||
|
replace-allow-list:
|
||||||
|
# pin versions
|
||||||
|
- k8s.io/api
|
||||||
|
- k8s.io/apiextensions-apiserver
|
||||||
|
- k8s.io/apimachinery
|
||||||
|
- k8s.io/client-go
|
||||||
|
- k8s.io/component-base
|
||||||
|
govet:
|
||||||
|
check-shadowing: true
|
||||||
|
enable-all: true
|
||||||
|
disable:
|
||||||
|
- fieldalignment
|
||||||
|
# see https://github.com/golangci/golangci-lint/issues/2649
|
||||||
|
- nilness
|
||||||
|
- unusedwrite
|
||||||
|
importas:
|
||||||
|
no-unaliased: true
|
||||||
|
alias:
|
||||||
|
- pkg: (k8s.io/api|k8s.io/apimachinery/pkg/apis)/([A-z0-9]+)/([A-z0-9]+)
|
||||||
|
alias: $2$3
|
||||||
|
lll:
|
||||||
|
line-length: 140
|
||||||
|
misspell:
|
||||||
|
locale: US
|
||||||
|
nolintlint:
|
||||||
|
allow-leading-space: true # don't require machine-readable nolint directives (i.e. with no leading space)
|
||||||
|
allow-unused: false # report any unused nolint directives
|
||||||
|
require-explanation: false # don't require an explanation for nolint directives
|
||||||
|
require-specific: true
|
||||||
|
|
||||||
|
linters:
|
||||||
|
disable-all: true
|
||||||
|
enable:
|
||||||
|
- contextcheck
|
||||||
|
- deadcode
|
||||||
|
- dogsled
|
||||||
|
- dupl
|
||||||
|
- errcheck
|
||||||
|
- errchkjson
|
||||||
|
- errname
|
||||||
|
- errorlint
|
||||||
|
- exhaustive
|
||||||
|
- exportloopref
|
||||||
|
- funlen
|
||||||
|
- gocognit
|
||||||
|
- goconst
|
||||||
|
# - gocritic
|
||||||
|
- gocyclo
|
||||||
|
- godox
|
||||||
|
- gofumpt
|
||||||
|
- goimports
|
||||||
|
- gomoddirectives
|
||||||
|
- gomnd
|
||||||
|
- gosec
|
||||||
|
- gosimple
|
||||||
|
- govet
|
||||||
|
- ifshort
|
||||||
|
- importas
|
||||||
|
- ineffassign
|
||||||
|
# - ireturn - enable later
|
||||||
|
- lll
|
||||||
|
- misspell
|
||||||
|
- nakedret
|
||||||
|
- nestif
|
||||||
|
- nilnil
|
||||||
|
- noctx
|
||||||
|
- nolintlint
|
||||||
|
- paralleltest
|
||||||
|
- prealloc
|
||||||
|
- predeclared
|
||||||
|
- promlinter
|
||||||
|
- staticcheck
|
||||||
|
- structcheck
|
||||||
|
- stylecheck
|
||||||
|
- tenv
|
||||||
|
- testpackage
|
||||||
|
- thelper
|
||||||
|
- typecheck
|
||||||
|
- unconvert
|
||||||
|
- unparam
|
||||||
|
- varcheck
|
||||||
|
- whitespace
|
||||||
|
# - unused
|
||||||
|
- wastedassign
|
||||||
|
|
||||||
|
issues:
|
||||||
|
# Excluding configuration per-path, per-linter, per-text and per-source
|
||||||
|
exclude-rules:
|
||||||
|
- path: _test\.go
|
||||||
|
linters:
|
||||||
|
- dupl
|
||||||
|
- funlen
|
||||||
|
- gocognit
|
||||||
|
- gomnd
|
||||||
|
- govet
|
||||||
|
- path: magefiles/
|
||||||
|
linters:
|
||||||
|
- deadcode
|
||||||
|
|
||||||
|
run:
|
||||||
|
skip-files:
|
||||||
|
- ".*.mock.\\.go$"
|
||||||
|
modules-download-mode: readonly
|
||||||
|
timeout: 5m
|
45
.goreleaser.yaml
Normal file
45
.goreleaser.yaml
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
# This is an example .goreleaser.yml file with some sensible defaults.
|
||||||
|
# Make sure to check the documentation at https://goreleaser.com
|
||||||
|
before:
|
||||||
|
hooks:
|
||||||
|
- go mod tidy
|
||||||
|
builds:
|
||||||
|
- id: kreaper
|
||||||
|
binary: kreaper
|
||||||
|
flags:
|
||||||
|
- -trimpath
|
||||||
|
env:
|
||||||
|
- CGO_ENABLED=0
|
||||||
|
goos:
|
||||||
|
- linux
|
||||||
|
- windows
|
||||||
|
- darwin
|
||||||
|
archives:
|
||||||
|
- builds:
|
||||||
|
- kreaper
|
||||||
|
replacements:
|
||||||
|
darwin: Darwin
|
||||||
|
linux: Linux
|
||||||
|
windows: Windows
|
||||||
|
386: i386
|
||||||
|
amd64: x86_64
|
||||||
|
checksum:
|
||||||
|
name_template: 'checksums.txt'
|
||||||
|
snapshot:
|
||||||
|
name_template: "{{ incpatch .Version }}-next"
|
||||||
|
changelog:
|
||||||
|
sort: asc
|
||||||
|
filters:
|
||||||
|
exclude:
|
||||||
|
- '^docs:'
|
||||||
|
- '^test:'
|
||||||
|
|
||||||
|
dockers:
|
||||||
|
- ids:
|
||||||
|
- kreaper
|
||||||
|
image_templates:
|
||||||
|
- ghcr.io/baez90/kreaper:latest
|
||||||
|
- ghcr.io/baez90/kreaper:{{ .Tag }}
|
||||||
|
- ghcr.io/baez90/kreaper:{{ .Major }}
|
||||||
|
- ghcr.io/baez90/kreaper:{{ .ShortCommit}}
|
||||||
|
dockerfile: deployments/Dockerfile
|
28
Tiltfile
Normal file
28
Tiltfile
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# -*- mode: Python -*-
|
||||||
|
|
||||||
|
local_resource(
|
||||||
|
'build',
|
||||||
|
'CGO_ENABLED=0 go build -trimpath -ldflags "-w -s" -installsuffix cgo -o dist/kreaper main.go',
|
||||||
|
deps=['main.go', './reaper'],
|
||||||
|
)
|
||||||
|
|
||||||
|
debug_dockerfile = """
|
||||||
|
FROM docker.io/alpine:3.15
|
||||||
|
|
||||||
|
COPY kreaper /usr/local/bin/
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/local/bin/kreaper"]
|
||||||
|
"""
|
||||||
|
|
||||||
|
custom_build(
|
||||||
|
'kreaper',
|
||||||
|
'docker build -f deployments/Dockerfile -t $EXPECTED_REF --build-arg BASE="docker.io/alpine:3.15" ./dist/',
|
||||||
|
entrypoint='/usr/local/bin/kreaper',
|
||||||
|
deps=['./dist/kreaper'],
|
||||||
|
live_update=[
|
||||||
|
sync('./dist/kreaper', '/usr/local/bin/kreaper'),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
k8s_yaml(['testdata/target_pod.yaml', 'testdata/deployment.yaml'])
|
||||||
|
k8s_resource('kreaper', resource_deps=['build'])
|
7
deployments/Dockerfile
Normal file
7
deployments/Dockerfile
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
ARG BASE="gcr.io/distroless/static:nonroot"
|
||||||
|
|
||||||
|
FROM $BASE
|
||||||
|
|
||||||
|
COPY kreaper /usr/local/bin/
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/local/bin/kreaper"]
|
18
go.mod
18
go.mod
|
@ -3,7 +3,9 @@ module github.com/baez90/kreaper
|
||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
go.uber.org/zap v1.21.0
|
||||||
k8s.io/api v0.23.5
|
k8s.io/api v0.23.5
|
||||||
|
k8s.io/apimachinery v0.23.5
|
||||||
k8s.io/client-go v0.23.5
|
k8s.io/client-go v0.23.5
|
||||||
sigs.k8s.io/controller-runtime v0.11.2
|
sigs.k8s.io/controller-runtime v0.11.2
|
||||||
)
|
)
|
||||||
|
@ -17,10 +19,14 @@ require (
|
||||||
github.com/google/go-cmp v0.5.5 // indirect
|
github.com/google/go-cmp v0.5.5 // indirect
|
||||||
github.com/google/gofuzz v1.1.0 // indirect
|
github.com/google/gofuzz v1.1.0 // indirect
|
||||||
github.com/googleapis/gnostic v0.5.5 // indirect
|
github.com/googleapis/gnostic v0.5.5 // indirect
|
||||||
|
github.com/imdario/mergo v0.3.12 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
go.uber.org/atomic v1.9.0 // indirect
|
||||||
|
go.uber.org/multierr v1.8.0 // indirect
|
||||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
|
golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
|
||||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect
|
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect
|
||||||
golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8 // indirect
|
golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8 // indirect
|
||||||
|
@ -32,8 +38,6 @@ require (
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
k8s.io/api v0.23.5 // indirect
|
|
||||||
k8s.io/apimachinery v0.23.5 // indirect
|
|
||||||
k8s.io/klog/v2 v2.30.0 // indirect
|
k8s.io/klog/v2 v2.30.0 // indirect
|
||||||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
|
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
|
||||||
k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect
|
k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect
|
||||||
|
@ -43,9 +47,9 @@ require (
|
||||||
)
|
)
|
||||||
|
|
||||||
replace (
|
replace (
|
||||||
k8s.io/api => k8s.io/api v0.23.1
|
k8s.io/api => k8s.io/api v0.23.5
|
||||||
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.23.1
|
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.23.5
|
||||||
k8s.io/apimachinery => k8s.io/apimachinery v0.23.1
|
k8s.io/apimachinery => k8s.io/apimachinery v0.23.5
|
||||||
k8s.io/client-go => k8s.io/client-go v0.23.1
|
k8s.io/client-go => k8s.io/client-go v0.23.5
|
||||||
k8s.io/component-base => k8s.io/component-base v0.23.1
|
k8s.io/component-base => k8s.io/component-base v0.23.5
|
||||||
)
|
)
|
||||||
|
|
33
go.sum
33
go.sum
|
@ -49,6 +49,8 @@ github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb0
|
||||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||||
|
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||||
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||||
|
@ -175,6 +177,7 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||||
|
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
@ -215,6 +218,7 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
|
||||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
|
github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||||
|
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
@ -248,9 +252,16 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||||
go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI=
|
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
|
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
||||||
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||||
|
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
|
||||||
|
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
|
||||||
|
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
|
||||||
|
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
||||||
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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
@ -606,13 +617,13 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||||
k8s.io/api v0.23.1 h1:ncu/qfBfUoClqwkTGbeRqqOqBCRoUAflMuOaOD7J0c8=
|
k8s.io/api v0.23.5 h1:zno3LUiMubxD/V1Zw3ijyKO3wxrhbUF1Ck+VjBvfaoA=
|
||||||
k8s.io/api v0.23.1/go.mod h1:WfXnOnwSqNtG62Y1CdjoMxh7r7u9QXGCkA1u0na2jgo=
|
k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8=
|
||||||
k8s.io/apiextensions-apiserver v0.23.1 h1:xxE0q1vLOVZiWORu1KwNRQFsGWtImueOrqSl13sS5EU=
|
k8s.io/apiextensions-apiserver v0.23.5 h1:5SKzdXyvIJKu+zbfPc3kCbWpbxi+O+zdmAJBm26UJqI=
|
||||||
k8s.io/apimachinery v0.23.1 h1:sfBjlDFwj2onG0Ijx5C+SrAoeUscPrmghm7wHP+uXlo=
|
k8s.io/apimachinery v0.23.5 h1:Va7dwhp8wgkUPWsEXk6XglXWU4IKYLKNlv8VkX7SDM0=
|
||||||
k8s.io/apimachinery v0.23.1/go.mod h1:SADt2Kl8/sttJ62RRsi9MIV4o8f5S3coArm0Iu3fBno=
|
k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
|
||||||
k8s.io/client-go v0.23.1 h1:Ma4Fhf/p07Nmj9yAB1H7UwbFHEBrSPg8lviR24U2GiQ=
|
k8s.io/client-go v0.23.5 h1:zUXHmEuqx0RY4+CsnkOn5l0GU+skkRXKGJrhmE2SLd8=
|
||||||
k8s.io/client-go v0.23.1/go.mod h1:6QSI8fEuqD4zgFK0xbdwfB/PthBsIxCJMa3s17WlcO0=
|
k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4=
|
||||||
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||||
|
@ -621,7 +632,6 @@ k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4=
|
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4=
|
||||||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
|
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
|
||||||
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
|
||||||
k8s.io/utils v0.0.0-20211116205334-6203023598ed h1:ck1fRPWPJWsMd8ZRFsWc6mh/zHp5fZ/shhbrgPUxDAE=
|
k8s.io/utils v0.0.0-20211116205334-6203023598ed h1:ck1fRPWPJWsMd8ZRFsWc6mh/zHp5fZ/shhbrgPUxDAE=
|
||||||
k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
|
@ -632,7 +642,6 @@ sigs.k8s.io/controller-runtime v0.11.2/go.mod h1:P6QCzrEjLaZGqHsfd+os7JQ+WFZhvB8
|
||||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s=
|
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s=
|
||||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
|
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||||
|
|
96
main.go
96
main.go
|
@ -3,9 +3,15 @@ package main
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"go.uber.org/zap/zapcore"
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
"k8s.io/client-go/util/homedir"
|
"k8s.io/client-go/util/homedir"
|
||||||
|
@ -14,36 +20,89 @@ import (
|
||||||
"github.com/baez90/kreaper/reaper"
|
"github.com/baez90/kreaper/reaper"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ReaperTarget string
|
const defaultKreaperLifetime = 5 * time.Minute
|
||||||
|
|
||||||
var (
|
var (
|
||||||
kubeconfig string
|
kubeconfig string
|
||||||
target reaper.Target
|
dryRun bool
|
||||||
lifetime time.Duration
|
logLevel *zapcore.Level
|
||||||
|
kreaper = reaper.Kreaper{
|
||||||
|
Target: lookupEnvOr[reaper.Target]("KREAPER_TARGET", "", reaper.ParseTarget),
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
prepareFlags()
|
prepareFlags()
|
||||||
|
setupLogging()
|
||||||
|
|
||||||
|
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
|
||||||
|
|
||||||
|
if err := run(ctx); err != nil {
|
||||||
|
cancel()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func run(ctx context.Context) error {
|
||||||
|
logger := zap.L()
|
||||||
|
|
||||||
restCfg, err := loadRestConfig()
|
restCfg, err := loadRestConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
logger.Error("Failed to get cluster config", zap.Error(err))
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
k8sClient, err := client.NewWithWatch(restCfg, client.Options{})
|
|
||||||
|
|
||||||
labels := client.MatchingLabels{
|
if kreaper.Client, err = client.NewWithWatch(restCfg, client.Options{}); err != nil {
|
||||||
"from": "value",
|
logger.Error("failed to prepare Kubernetes API client", zap.Error(err))
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
k8sClient.Watch(context.Background(), nil, labels)
|
|
||||||
|
return kreaper.Kill(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupLogging() {
|
||||||
|
cfg := zap.NewProductionConfig()
|
||||||
|
cfg.Level = zap.NewAtomicLevelAt(*logLevel)
|
||||||
|
logger, err := cfg.Build()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to setup logging: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
zap.ReplaceGlobals(logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareFlags() {
|
func prepareFlags() {
|
||||||
flag.Var(&target, "target", "Target that should be monitored")
|
logLevel = zap.LevelFlag("log-level", zapcore.InfoLevel, "Log level to use")
|
||||||
flag.DurationVar(&lifetime, "lifetime", 5*time.Minute, "Lifetime after which all matching targets will be deleted")
|
flag.Var(&kreaper.Target, "target", "Target that should be monitored")
|
||||||
|
|
||||||
|
flag.BoolVar(
|
||||||
|
&dryRun,
|
||||||
|
"dry-run",
|
||||||
|
lookupEnvOr("KREAPER_DRY_RUN", false, strconv.ParseBool),
|
||||||
|
"Don't actually delete anything but only list all found pods matching the target - env variable: KREAPER_DRY_RUN",
|
||||||
|
)
|
||||||
|
|
||||||
|
flag.DurationVar(
|
||||||
|
&kreaper.Lifetime,
|
||||||
|
"lifetime",
|
||||||
|
lookupEnvOr("KREAPER_LIFETIME", defaultKreaperLifetime, time.ParseDuration),
|
||||||
|
"Lifetime after which all matching targets will be deleted - env variable: KREAPER_LIFETIME",
|
||||||
|
)
|
||||||
|
|
||||||
|
flag.StringVar(
|
||||||
|
&kreaper.TargetNamespace,
|
||||||
|
"target-namespace",
|
||||||
|
lookupEnvOr("KREAPER_TARGET_NAMESPACE", "default", identity[string]),
|
||||||
|
"Set target namespace in which kreaper will look for pods - env variable: KREAPER_TARGET_NAMESPACE",
|
||||||
|
)
|
||||||
|
|
||||||
if home := homedir.HomeDir(); home != "" {
|
if home := homedir.HomeDir(); home != "" {
|
||||||
flag.StringVar(&kubeconfig, "kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
|
flag.StringVar(&kubeconfig, "kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
|
||||||
} else {
|
} else {
|
||||||
flag.StringVar(&kubeconfig, "kubeconfig", "", "absolute path to the kubeconfig file")
|
flag.StringVar(&kubeconfig, "kubeconfig", "", "absolute path to the kubeconfig file")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadRestConfig() (cfg *rest.Config, err error) {
|
func loadRestConfig() (cfg *rest.Config, err error) {
|
||||||
|
@ -53,3 +112,20 @@ func loadRestConfig() (cfg *rest.Config, err error) {
|
||||||
|
|
||||||
return clientcmd.BuildConfigFromFlags("", kubeconfig)
|
return clientcmd.BuildConfigFromFlags("", kubeconfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func lookupEnvOr[T any](envKey string, fallback T, parse func(envVal string) (T, error)) T {
|
||||||
|
envVal := os.Getenv(envKey)
|
||||||
|
if envVal == "" {
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
if parsed, err := parse(envVal); err != nil {
|
||||||
|
return fallback
|
||||||
|
} else {
|
||||||
|
return parsed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func identity[T any](in T) (T, error) {
|
||||||
|
return in, nil
|
||||||
|
}
|
||||||
|
|
117
reaper/reaper.go
117
reaper/reaper.go
|
@ -1,8 +1,117 @@
|
||||||
package reaper
|
package reaper
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
type Reaper struct {
|
"go.uber.org/zap"
|
||||||
Lifetime time.Duration
|
corev1 "k8s.io/api/core/v1"
|
||||||
Target Target
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Kreaper struct {
|
||||||
|
labelSelector labels.Selector
|
||||||
|
Client client.WithWatch
|
||||||
|
Lifetime time.Duration
|
||||||
|
Target Target
|
||||||
|
TargetNamespace string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k Kreaper) Kill(ctx context.Context) (err error) {
|
||||||
|
var (
|
||||||
|
logger = zap.L()
|
||||||
|
podList corev1.PodList
|
||||||
|
)
|
||||||
|
|
||||||
|
if k.labelSelector, err = k.Target.Selector(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := []client.ListOption{
|
||||||
|
client.MatchingLabelsSelector{Selector: k.labelSelector},
|
||||||
|
client.InNamespace(k.TargetNamespace),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = k.Client.List(ctx, &podList, opts...); err != nil {
|
||||||
|
logger.Error("failed to list", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(podList.Items) < 1 {
|
||||||
|
logger.Warn("No pod targets found")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range podList.Items {
|
||||||
|
logger.Info("Found pod", zap.String("pod_name", podList.Items[i].Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
watcher, err := k.Client.Watch(ctx, &podList, opts...)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("failed to setup watch", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer watcher.Stop()
|
||||||
|
done, err := k.startPodWatcher(ctx, podList, opts)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-time.After(k.Lifetime):
|
||||||
|
logger.Info("Reached end of lifetime force delete all matching pods")
|
||||||
|
if err := k.forceDeleteAll(ctx); err != nil {
|
||||||
|
logger.Error("Failed to delete all pods", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case <-done:
|
||||||
|
logger.Info("All pods deleted")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *Kreaper) startPodWatcher(ctx context.Context, podList corev1.PodList, opts []client.ListOption) (<-chan struct{}, error) {
|
||||||
|
logger := zap.L()
|
||||||
|
watcher, err := k.Client.Watch(ctx, &podList, opts...)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("failed to setup watch", zap.Error(err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer watcher.Stop()
|
||||||
|
|
||||||
|
for ev := range watcher.ResultChan() {
|
||||||
|
if ev.Type != watch.Deleted {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := k.Client.List(ctx, &podList, opts...); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(podList.Items) == 0 {
|
||||||
|
close(done)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return done, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *Kreaper) forceDeleteAll(ctx context.Context) error {
|
||||||
|
return k.Client.DeleteAllOf(
|
||||||
|
ctx,
|
||||||
|
new(corev1.Pod),
|
||||||
|
client.InNamespace(k.TargetNamespace),
|
||||||
|
client.PropagationPolicy(metav1.DeletePropagationForeground),
|
||||||
|
client.MatchingLabelsSelector{
|
||||||
|
Selector: k.labelSelector,
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,15 +6,24 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrNotAVAlidTarget = errors.New("not a valid target")
|
var ErrNotAVAlidTarget = errors.New("not a valid target")
|
||||||
|
|
||||||
var _ flag.Value = (*Target)(nil)
|
var _ flag.Value = (*Target)(nil)
|
||||||
|
|
||||||
|
func ParseTarget(val string) (Target, error) {
|
||||||
|
t := Target(val)
|
||||||
|
if _, err := t.Selector(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
|
|
||||||
type Target string
|
type Target string
|
||||||
|
|
||||||
func (t Target) Selector() (*metav1.LabelSelector, error) {
|
func (t Target) Selector() (labels.Selector, error) {
|
||||||
s := string(t)
|
s := string(t)
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return nil, ErrNotAVAlidTarget
|
return nil, ErrNotAVAlidTarget
|
||||||
|
@ -25,11 +34,13 @@ func (t Target) Selector() (*metav1.LabelSelector, error) {
|
||||||
return nil, ErrNotAVAlidTarget
|
return nil, ErrNotAVAlidTarget
|
||||||
}
|
}
|
||||||
|
|
||||||
return &metav1.LabelSelector{
|
sel := &metav1.LabelSelector{
|
||||||
MatchLabels: map[string]string{
|
MatchLabels: map[string]string{
|
||||||
key: val,
|
key: val,
|
||||||
},
|
},
|
||||||
}, nil
|
}
|
||||||
|
|
||||||
|
return metav1.LabelSelectorAsSelector(sel)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Target) String() string {
|
func (t Target) String() string {
|
||||||
|
|
3
scripts/build.sh
Executable file
3
scripts/build.sh
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
CGO_ENABLED=0 go build -trimpath -ldflags "-w -s" -installsuffix cgo -o dist/kreaper main.go
|
61
testdata/deployment.yaml
vendored
Normal file
61
testdata/deployment.yaml
vendored
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: kreaper-debug
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
name: kreaper-debug
|
||||||
|
rules:
|
||||||
|
- verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- deletecollection
|
||||||
|
apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- pods
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: kreaper-debug
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: kreaper-debug
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: kreaper-debug
|
||||||
|
---
|
||||||
|
apiVersion: batch/v1
|
||||||
|
kind: Job
|
||||||
|
metadata:
|
||||||
|
name: kreaper
|
||||||
|
spec:
|
||||||
|
backoffLimit: 3
|
||||||
|
completions: 1
|
||||||
|
ttlSecondsAfterFinished: 30
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: kreaper
|
||||||
|
spec:
|
||||||
|
restartPolicy: OnFailure
|
||||||
|
serviceAccountName: kreaper-debug
|
||||||
|
containers:
|
||||||
|
- name: kreaper
|
||||||
|
image: kreaper
|
||||||
|
args:
|
||||||
|
- -log-level=debug
|
||||||
|
env:
|
||||||
|
- name: KREAPER_TARGET
|
||||||
|
value: org.testcontainers.golang/sessionID=ee8dcc4d-72b5-4e77-8244-37abe525f948
|
||||||
|
- name: KREAPER_LIFETIME
|
||||||
|
value: "30s"
|
||||||
|
- name: KREAPER_TARGET_NAMESPACE
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
fieldPath: metadata.namespace
|
12
testdata/kind.yaml
vendored
Normal file
12
testdata/kind.yaml
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Creates a kind cluster with Kind's custom cluster config
|
||||||
|
# https://pkg.go.dev/sigs.k8s.io/kind/pkg/apis/config/v1alpha4#Cluster
|
||||||
|
# Creates a cluster with 2 nodes.
|
||||||
|
apiVersion: ctlptl.dev/v1alpha1
|
||||||
|
kind: Cluster
|
||||||
|
product: kind
|
||||||
|
registry: ctlptl-registry
|
||||||
|
kindV1Alpha4Cluster:
|
||||||
|
name: kind
|
||||||
|
nodes:
|
||||||
|
- role: control-plane
|
||||||
|
- role: worker
|
24
testdata/target_pod.yaml
vendored
Normal file
24
testdata/target_pod.yaml
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: kreaper-target
|
||||||
|
labels:
|
||||||
|
org.testcontainers.golang/sessionID: ee8dcc4d-72b5-4e77-8244-37abe525f948
|
||||||
|
app.kubernetes.io/created-by: testcontainers-go
|
||||||
|
app.kubernetes.io/managed-by: testcontainers-go
|
||||||
|
spec:
|
||||||
|
terminationGracePeriodSeconds: 1
|
||||||
|
containers:
|
||||||
|
- name: busybox
|
||||||
|
image: docker.io/busybox:latest
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- "sleep 15 && touch /tmp/healthy && sleep 7200"
|
||||||
|
startupProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- cat
|
||||||
|
- /tmp/healthy
|
||||||
|
periodSeconds: 3
|
||||||
|
failureThreshold: 10
|
Reference in a new issue