okay it at least compiles dunno if it does anything yet.
ci/woodpecker/push/woodpecker Pipeline was successful Details

This commit is contained in:
Colin 2024-06-11 17:21:21 -04:00
parent 9428343a52
commit 40ae3fc6fe
21 changed files with 226 additions and 416 deletions

View File

@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
ARCHITECTURES=("linux/amd64" "linux/arm64" "darwin/amd64" "windows/amd64") ARCHITECTURES=("linux/amd64" "linux/arm64" "darwin/amd64" "darwin/arm64" "windows/amd64")
PROJECT_NAME=$(basename "$PWD") PROJECT_NAME=$(basename "$(pwd)")
prepare_build() { prepare_build() {
mkdir -p dist build_logs mkdir -p dist build_logs
@ -15,16 +15,16 @@ build_binary() {
local os=$1 local os=$1
local arch=$2 local arch=$2
local output="dist/${PROJECT_NAME}_${os}_${arch}" local output="dist/${PROJECT_NAME}_${os}_${arch}"
env GOOS=$os GOARCH=$arch go build -o $output . &> build_logs/${os}_${arch}.log env GOOS=$os GOARCH=$arch go build -o $output . &> "build_logs/${os}_${arch}.log"
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Build failed for $os/$arch" >> build_logs/error.log echo "Build failed for $os/$arch" >> "build_logs/error.log"
else else
echo "Build succeeded for $os/$arch" echo "Build succeeded for $os/$arch"
fi fi
if [ "$os" == "linux" ]; then if [ "$os" == "linux" ]; then
env GOOS=$os GOARCH=$arch CGO_ENABLED=0 go build -a -ldflags '-extldflags "-static"' -o ${output}_static . &> build_logs/${os}_${arch}_static.log env GOOS=$os GOARCH=$arch CGO_ENABLED=0 go build -a -ldflags '-extldflags "-static"' -o "${output}_static" . &> "build_logs/${os}_${arch}_static.log"
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Static build failed for $os/$arch" >> build_logs/error.log echo "Static build failed for $os/$arch" >> "build_logs/error.log"
else else
echo "Static build succeeded for $os/$arch" echo "Static build succeeded for $os/$arch"
fi fi

View File

@ -1,3 +0,0 @@
# oculus
./main.go:38:67: undefined: types.ContainerListOptions
./main.go:119:4: savedDiffs declared and not used

View File

View File

@ -1,6 +0,0 @@
Build failed for linux/amd64
Static build failed for linux/amd64
Build failed for linux/arm64
Static build failed for linux/arm64
Build failed for darwin/amd64
Build failed for windows/amd64

View File

@ -1,3 +0,0 @@
# oculus
./main.go:38:67: undefined: types.ContainerListOptions
./main.go:119:4: savedDiffs declared and not used

View File

@ -1,3 +0,0 @@
# oculus
./main.go:38:67: undefined: types.ContainerListOptions
./main.go:119:4: savedDiffs declared and not used

View File

@ -1,3 +0,0 @@
# oculus
./main.go:38:67: undefined: types.ContainerListOptions
./main.go:119:4: savedDiffs declared and not used

View File

@ -1,3 +0,0 @@
# oculus
./main.go:38:67: undefined: types.ContainerListOptions
./main.go:119:4: savedDiffs declared and not used

View File

@ -1,3 +0,0 @@
# oculus
./main.go:38:67: undefined: types.ContainerListOptions
./main.go:119:4: savedDiffs declared and not used

64
container_diffs.sh Normal file
View File

@ -0,0 +1,64 @@
#!/bin/bash
# Function to process diffs and check ignores
process_container() {
local container_id=$1
local mode=$2
# Get the container labels
labels=$(docker inspect --format '{{json .Config.Labels}}' "$container_id")
cname=$(echo "$labels" | jq -r '.["oculus.cname"]')
ignores=$(echo "$labels" | jq -r '.["oculus.ignores"]')
# Get the diff
diff_output=$(docker diff "$container_id")
# Process ignores
if [ "$ignores" != "null" ]; then
IFS=',' read -ra ignore_array <<< "$ignores"
for ignore in "${ignore_array[@]}"; do
diff_output=$(echo "$diff_output" | grep -v "$ignore")
done
fi
# Write the diff output to a file
echo "$diff_output" > "${cname}.diff"
if [ "$mode" == "monitor" ]; then
# Check if there are any changes left after applying ignores
if [ -n "$diff_output" ]; then
# Send notification using go-glitch
echo "$diff_output" | go-glitch
fi
fi
}
export -f process_container
# Get the list of running containers
containers=$(docker ps -q)
# Check if there are no running containers
if [ -z "$containers" ]; then
echo "No running containers found."
exit 0
fi
# Iterate over each container and process based on labels
for container in $containers; do
labels=$(docker inspect --format '{{json .Config.Labels}}' "$container")
enable=$(echo "$labels" | jq -r '.["oculus.enable"]')
if [ "$enable" == "monitor" ]; then
frequency=$(echo "$labels" | jq -r '.["oculus.frequency"]')
if [ "$frequency" == "null" ]; then
frequency="300s" # Default frequency if not set
fi
# Run the process_container function with monitor mode
echo "$container monitor" | parallel process_container
sleep "${frequency}"
elif [ "$enable" == "profile" ]; then
# Run the process_container function with profile mode
echo "$container profile" | parallel process_container
fi
done

BIN
dist/oculus-testbed_darwin_amd64 vendored Executable file

Binary file not shown.

BIN
dist/oculus-testbed_darwin_arm64 vendored Executable file

Binary file not shown.

BIN
dist/oculus-testbed_linux_amd64 vendored Executable file

Binary file not shown.

BIN
dist/oculus-testbed_linux_amd64_static vendored Executable file

Binary file not shown.

BIN
dist/oculus-testbed_linux_arm64 vendored Executable file

Binary file not shown.

BIN
dist/oculus-testbed_linux_arm64_static vendored Executable file

Binary file not shown.

BIN
dist/oculus-testbed_windows_amd64 vendored Executable file

Binary file not shown.

29
go.mod
View File

@ -1,32 +1,3 @@
module oculus module oculus
go 1.21.1 go 1.21.1
require github.com/docker/docker v26.1.4+incompatible
require (
github.com/Microsoft/go-winio v0.4.14 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.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/image-spec v1.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 // indirect
go.opentelemetry.io/otel v1.27.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0 // indirect
go.opentelemetry.io/otel/metric v1.27.0 // indirect
go.opentelemetry.io/otel/sdk v1.27.0 // indirect
go.opentelemetry.io/otel/trace v1.27.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/time v0.5.0 // indirect
gotest.tools/v3 v3.5.1 // indirect
)

121
go.sum
View File

@ -1,121 +0,0 @@
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
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/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v26.1.4+incompatible h1:vuTpXDuoga+Z38m1OZHzl7NKisKWaWlhjQk7IDPSLsU=
github.com/docker/docker v26.1.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
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/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
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/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/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.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
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.52.0 h1:9l89oX4ba9kHbBol3Xin3leYJ+252h0zszDtBwyKe2A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0/go.mod h1:XLZfZboOJWHNKUv7eH0inh0E9VV6eWDFB/9yJyTLPp0=
go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg=
go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 h1:R9DE4kQ4k+YtfLI2ULwX82VtNQ2J8yZmA7ZIF/D+7Mc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0/go.mod h1:OQFyQVrDlbe+R7xrEyDr/2Wr67Ol0hRUgsfA+V5A95s=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0 h1:QY7/0NeRPKlzusf40ZE4t1VlMKbqSNT7cJRYzWuja0s=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.27.0/go.mod h1:HVkSiDhTM9BoUJU8qE6j2eSWLLXvi1USXjyd2BXT8PY=
go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik=
go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak=
go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI=
go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A=
go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw=
go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4=
go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94=
go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A=
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/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
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-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 h1:P8OJ/WCl/Xo4E4zoe4/bifHpSmmKwARqyqE4nW6J2GQ=
google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:RGnPtTG7r4i8sPlNyDeikXF99hMM+hN6QMm4ooG9g2g=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 h1:AgADTJarZTBqgjiUzRgfaBchgYB3/WFTC80GPwsMcRI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=

358
main.go
View File

@ -1,260 +1,146 @@
package main package main
import ( import (
"context"
"encoding/json"
"fmt" "fmt"
"log" "log"
"os" "os"
"os/exec" "os/exec"
"os/signal"
"path/filepath"
"strings" "strings"
"syscall"
"time" "time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
) )
const ( type ContainerInfo struct {
notifyScript = "/notify.sh" ID string
logDir = "/log" Name string
) Interval time.Duration
Ignores []string
type ContainerDiff struct {
ID string
Image string
Labels map[string]string
}
type FileChange struct {
Path string
Kind string
}
func getRunningContainers(cli *client.Client) ([]ContainerDiff, error) {
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
if err != nil {
return nil, err
}
var diffs []ContainerDiff
for _, container := range containers {
if _, ok := container.Labels["oculus.cname"]; ok {
diffs = append(diffs, ContainerDiff{
ID: container.ID,
Image: container.Image,
Labels: container.Labels,
})
}
}
return diffs, nil
}
func saveDiffs(diffs []FileChange, filePath string) error {
data, err := json.Marshal(diffs)
if err != nil {
return err
}
return os.WriteFile(filePath, data, 0644)
}
func loadDiffs(filePath string) ([]FileChange, error) {
data, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
var diffs []FileChange
err = json.Unmarshal(data, &diffs)
return diffs, err
}
func shouldIgnore(change string, ignoreList []string) bool {
for _, ignore := range ignoreList {
if strings.Contains(change, ignore) {
return true
}
}
return false
}
func logDetection(containerID, message string) {
logFilePath := filepath.Join(logDir, fmt.Sprintf("%s.log", containerID))
f, err := os.OpenFile(logFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Printf("Error opening log file: %v", err)
return
}
defer f.Close()
log.SetOutput(f)
log.Println(message)
sendToGlitchtip(logFilePath)
}
func sendToGlitchtip(logFilePath string) {
if dsn := os.Getenv("GLITCHTIP_DSN"); dsn != "" {
cmd := exec.Command("go-glitch", logFilePath)
err := cmd.Run()
if err != nil {
log.Printf("Error sending to Go Glitch: %v", err)
}
}
}
func compareContainers(cli *client.Client, mode string) {
currentDiffs, err := getRunningContainers(cli)
if err != nil {
log.Fatalf("Error getting current containers: %v", err)
}
for _, current := range currentDiffs {
if current.Labels["oculus.mode"] == mode {
filePath := filepath.Join(logDir, fmt.Sprintf("%s.json", current.Labels["oculus.cname"]))
savedDiffs, err := loadDiffs(filePath)
if err != nil {
log.Printf("Error loading saved diffs for %s: %v", current.ID, err)
savedDiffs = []FileChange{} // Initialize to an empty slice
}
ignoreList := strings.Split(current.Labels["oculus.ignorelist"], ",")
currentChanges, err := cli.ContainerDiff(context.Background(), current.ID)
if err != nil {
log.Printf("Error getting container diff for %s: %v", current.ID, err)
continue
}
var changes []FileChange
for _, change := range currentChanges {
path := change.Path
kind := ""
switch change.Kind {
case 0:
kind = "Modified"
case 1:
kind = "Added"
case 2:
kind = "Deleted"
}
if !shouldIgnore(path, ignoreList) {
changes = append(changes, FileChange{
Path: path,
Kind: kind,
})
}
}
if mode == "monitor" {
err = saveDiffs(changes, filePath)
if err != nil {
log.Fatalf("Error saving diffs: %v", err)
}
} else if mode == "report" {
for _, change := range changes {
message := fmt.Sprintf("Container %s changed: %s %s", current.ID, change.Kind, change.Path)
logDetection(current.Labels["oculus.cname"], message)
runNotifyScript(filepath.Join(logDir, fmt.Sprintf("%s.log", current.Labels["oculus.cname"])))
}
}
}
}
}
func runNotifyScript(logFilePath string) {
cmd := exec.Command(notifyScript, logFilePath)
err := cmd.Run()
if err != nil {
log.Printf("Error running notify script: %v", err)
}
}
func watchDockerEvents(cli *client.Client) {
eventFilter := filters.NewArgs()
eventFilter.Add("type", "container")
eventFilter.Add("event", "start")
eventFilter.Add("event", "stop")
eventFilter.Add("event", "destroy")
messages, errs := cli.Events(context.Background(), types.EventsOptions{
Filters: eventFilter,
})
for {
select {
case event := <-messages:
log.Printf("Docker event received: %s for container %s", event.Action, event.ID)
compareContainers(cli, "monitor")
case err := <-errs:
log.Printf("Error watching Docker events: %v", err)
return
}
}
}
func monitorContainers(cli *client.Client, interval time.Duration) {
ticker := time.NewTicker(interval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
compareContainers(cli, "monitor")
}
}
}
func reportContainers(cli *client.Client, interval time.Duration) {
ticker := time.NewTicker(interval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
compareContainers(cli, "report")
}
}
} }
func main() { func main() {
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) for {
containers, err := getContainers()
if err != nil {
log.Printf("Error listing containers: %v", err)
time.Sleep(1 * time.Minute)
continue
}
for _, container := range containers {
go monitorContainer(container)
}
// Sleep for 1 minute before checking for new containers again
time.Sleep(1 * time.Minute)
}
}
func getContainers() ([]ContainerInfo, error) {
output, err := exec.Command("docker", "ps", "--format", "{{.ID}} {{.Label \"oculus.enable\"}} {{.Label \"oculus.interval\"}} {{.Label \"oculus.cname\"}} {{.Label \"oculus.ignores\"}}").Output()
if err != nil { if err != nil {
log.Fatalf("Error creating Docker client: %v", err) return nil, err
} }
go watchDockerEvents(cli) lines := strings.Split(string(output), "\n")
var containers []ContainerInfo
// Get running containers and set up monitoring intervals for _, line := range lines {
containers, err := getRunningContainers(cli) if line == "" {
if err != nil { continue
log.Fatalf("Error getting running containers: %v", err) }
parts := strings.Fields(line)
if len(parts) < 2 || parts[1] == "" {
continue
}
id := parts[0]
intervalStr := "300s"
if len(parts) > 2 && parts[2] != "" {
intervalStr = parts[2]
}
interval, err := time.ParseDuration(intervalStr)
if err != nil {
log.Printf("Invalid interval format for container %s: %v", id, err)
continue
}
cname := id
if len(parts) > 3 && parts[3] != "" {
cname = parts[3]
}
ignores := []string{}
if len(parts) > 4 && parts[4] != "" {
ignores = strings.Split(parts[4], ",")
}
containers = append(containers, ContainerInfo{
ID: id,
Name: cname,
Interval: interval,
Ignores: ignores,
})
} }
for _, container := range containers { return containers, nil
if mode, ok := container.Labels["oculus.mode"]; ok { }
intervalStr := container.Labels["oculus.interval"]
interval, err := time.ParseDuration(intervalStr)
if err != nil {
log.Fatalf("Invalid interval format for container %s: %v", container.ID, err)
}
if mode == "monitor" { func monitorContainer(container ContainerInfo) {
go monitorContainers(cli, interval) for {
} else if mode == "report" { checkDiff(container)
go reportContainers(cli, interval) time.Sleep(container.Interval)
} }
}
func checkDiff(container ContainerInfo) {
cmd := exec.Command("docker", "diff", container.ID)
output, err := cmd.Output()
if err != nil {
log.Printf("Error running docker diff for container %s: %v", container.ID, err)
return
}
diffOutput := string(output)
for _, ignore := range container.Ignores {
diffOutput = removeIgnoredPaths(diffOutput, ignore)
}
if diffOutput != "" {
// Write diff output to a file
filename := fmt.Sprintf("%s.diff", container.Name)
err = writeToFile(filename, diffOutput)
if err != nil {
log.Printf("Error writing diff to file for container %s: %v", container.ID, err)
}
// Send notification using go-glitch
cmd = exec.Command("go-glitch")
cmd.Stdin = strings.NewReader(diffOutput)
err = cmd.Run()
if err != nil {
log.Printf("Error sending notification for container %s: %v", container.ID, err)
} }
} }
}
// Graceful shutdown handling
sigs := make(chan os.Signal, 1) func removeIgnoredPaths(diffOutput string, ignore string) string {
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) lines := strings.Split(diffOutput, "\n")
<-sigs filteredLines := []string{}
log.Println("Shutting down...") for _, line := range lines {
if !strings.Contains(line, ignore) {
filteredLines = append(filteredLines, line)
}
}
return strings.Join(filteredLines, "\n")
}
func writeToFile(filename, content string) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
_, err = file.WriteString(content)
return err
} }

34
process_diffs.sh Normal file
View File

@ -0,0 +1,34 @@
#!/bin/bash
# Function to process diffs and check ignores
process_diff() {
local container_id=$1
local cname=$2
local ignores=$3
# Get the diff
diff_output=$(docker diff $container_id)
# Process ignores
if [ -n "$ignores" ]; then
IFS=',' read -ra ignore_array <<< "$ignores"
for ignore in "${ignore_array[@]}"; do
diff_output=$(echo "$diff_output" | grep -v "$ignore")
done
fi
# Write the diff output to a file
echo "$diff_output" > "${cname}.diff"
# Check if there are any changes left after applying ignores
if [ -n "$diff_output" ]; then
# Send notification using go-glitch
echo "$diff_output" | go-glitch
fi
}
export -f process_diff
# Read containers.txt and process each line in parallel
cat containers.txt | parallel --colsep ' ' 'process_diff {1} {2} {3}'
./