oculus stable
ci/woodpecker/push/woodpecker Pipeline was successful
Details
ci/woodpecker/push/woodpecker Pipeline was successful
Details
This commit is contained in:
parent
56f168efb7
commit
653688c6a0
|
@ -0,0 +1,2 @@
|
|||
diffs
|
||||
build_logs
|
|
@ -0,0 +1,145 @@
|
|||
# build 1
|
||||
labels:
|
||||
hostname: "macmini7"
|
||||
clone:
|
||||
git:
|
||||
image: woodpeckerci/plugin-git
|
||||
settings:
|
||||
partial: false
|
||||
depth: 1
|
||||
steps:
|
||||
# Build Step for staging Branch
|
||||
build-staging:
|
||||
name: build-staging
|
||||
image: woodpeckerci/plugin-docker-buildx
|
||||
secrets: [REGISTRY_USER, REGISTRY_PASSWORD]
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
commands:
|
||||
- echo "Building application for staging branch"
|
||||
- echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us
|
||||
- echo compose build
|
||||
- docker compose -f docker-compose.staging.yml build --no-cache
|
||||
when:
|
||||
branch: main
|
||||
event: push
|
||||
# path:
|
||||
# include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ]
|
||||
|
||||
deploy-new:
|
||||
name: deploy-new
|
||||
when:
|
||||
branch: main
|
||||
# path:
|
||||
# include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ]
|
||||
image: woodpeckerci/plugin-docker-buildx
|
||||
secrets: [REGISTRY_USER, REGISTRY_PASSWORD]
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
commands:
|
||||
- echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us
|
||||
- echo compose push
|
||||
- docker compose -f docker-compose.staging.yml push
|
||||
# - docker stack deploy --with-registry-auth -c ./stack.staging.yml $${CI_REPO_NAME}-staging
|
||||
|
||||
# # Wait for Deploy to Complete
|
||||
# wait-for-deploy-staging:
|
||||
# name: wait-for-deploy-staging
|
||||
# image: woodpeckerci/plugin-git
|
||||
# commands:
|
||||
# - echo "Waiting for staging deploy step to complete rollout."
|
||||
# - sleep 60
|
||||
# when:
|
||||
# - branch: main
|
||||
# - event: push
|
||||
|
||||
# # Run Automated Tests on staging Branch
|
||||
# test-staging:
|
||||
# name: run-tests-staging
|
||||
# image: git.nixc.us/colin/playwright:latest
|
||||
# secrets: [ base_url ]
|
||||
# when:
|
||||
# - branch: main
|
||||
# - event: push
|
||||
# - path:
|
||||
# include: [ 'tests/', 'src/','docker-compose.staging.yml', 'docker-compose.production.yml', '*.tests.ts' ] # Specify paths relevant to tests
|
||||
# volumes:
|
||||
# - /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
|
||||
cleanup-staging:
|
||||
name: cleanup-staging
|
||||
when:
|
||||
branch: main
|
||||
# path:
|
||||
# include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ]
|
||||
image: woodpeckerci/plugin-docker-buildx
|
||||
secrets: [REGISTRY_USER, REGISTRY_PASSWORD]
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
commands:
|
||||
# - docker stack rm $${CI_REPO_NAME}-staging
|
||||
## added fault tolerance for docker stack rm
|
||||
- for i in {1..5}; do docker stack rm ${CI_REPO_NAME}-staging && break || sleep 10; done
|
||||
- docker compose -f docker-compose.staging.yml down
|
||||
- docker compose -f docker-compose.staging.yml rm -f
|
||||
|
||||
# Build Step for staging Branch
|
||||
build-push-production:
|
||||
name: build-push-production
|
||||
image: woodpeckerci/plugin-docker-buildx
|
||||
secrets: [REGISTRY_USER, REGISTRY_PASSWORD]
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
commands:
|
||||
- echo "Building application for staging branch"
|
||||
- echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us
|
||||
- echo compose build
|
||||
- docker compose -f docker-compose.production.yml build --no-cache
|
||||
- docker compose -f docker-compose.production.yml push
|
||||
when:
|
||||
branch: main
|
||||
event: [push, cron]
|
||||
# path:
|
||||
# include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ]
|
||||
|
||||
# Deploy to Production Branch
|
||||
deploy-production:
|
||||
name: deploy-production
|
||||
image: woodpeckerci/plugin-docker-buildx
|
||||
secrets: [REGISTRY_USER, REGISTRY_PASSWORD]
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
commands:
|
||||
- echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us
|
||||
- docker stack deploy --with-registry-auth -c ./stack.production.yml $${CI_REPO_NAME}
|
||||
# - docker image rm git.nixc.us/colin/$${CI_REPO_NAME}:production
|
||||
when:
|
||||
branch: main
|
||||
event: [push, cron]
|
||||
# path:
|
||||
# include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ]
|
||||
|
||||
|
||||
# # Wait for Deploy to Complete
|
||||
# wait-for-deploy-production:
|
||||
# name: wait-for-deploy-production
|
||||
# image: woodpeckerci/plugin-git
|
||||
# commands:
|
||||
# - echo "Waiting for deploy step to complete rollout."
|
||||
# - sleep 60
|
||||
# when:
|
||||
# branch: main
|
||||
# event: push
|
||||
|
||||
# # Run Post-Deployment Smoke Tests
|
||||
# post-deploy-smoke-tests-git-nixc-us:
|
||||
# name: run-post-deploy-smoke-tests-git-nixc-us
|
||||
# image: git.nixc.us/colin/playwright:latest
|
||||
# # secrets: [TEST_USER, TEST_PASSWORD]
|
||||
# environment:
|
||||
# - BASE_URL=https://git.nixc.us
|
||||
# when:
|
||||
# branch: main
|
||||
# event: push
|
||||
# # path:
|
||||
# # include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ]
|
|
@ -0,0 +1,108 @@
|
|||
<!-- build 0 -->
|
||||
# Oculus Toolchain
|
||||
|
||||
Oculus is a toolchain for monitoring and handling Docker container diffs. It includes three main components:
|
||||
- **filter**: Filters the diff outputs based on ignore patterns.
|
||||
- **api**: Provides an API to fetch container details and diffs.
|
||||
- **main**: The main monitoring application that uses the API and filter components to manage container diffs.
|
||||
|
||||
## Installation
|
||||
|
||||
To install the Oculus toolchain, you can use the provided `install.sh` script. This script will download and install the appropriate binaries for your system.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- **curl**: Make sure `curl` is installed on your system.
|
||||
- **sudo**: Required if you do not have write permission to `/usr/local/bin`.
|
||||
|
||||
### Installation Steps
|
||||
|
||||
1. **Download the Install Script**:
|
||||
```sh
|
||||
curl -sSL https://git.nixc.us/colin/Oculus/raw/branch/main/install.sh -o install.sh
|
||||
```
|
||||
|
||||
2. **Make the Script Executable**:
|
||||
```sh
|
||||
chmod +x install.sh
|
||||
```
|
||||
|
||||
3. **Run the Install Script**:
|
||||
```sh
|
||||
./install.sh
|
||||
```
|
||||
|
||||
This will download and install the following components to `/usr/local/bin`:
|
||||
- `oculus_filter`
|
||||
- `oculus_api`
|
||||
- `oculus_main`
|
||||
|
||||
## Usage
|
||||
|
||||
After installation, you can start using the Oculus toolchain. Below are the basic usage instructions for each component:
|
||||
|
||||
### Starting the API Server
|
||||
|
||||
To start the API server, run:
|
||||
```sh
|
||||
oculus_api
|
||||
```
|
||||
This will start the API server on port 8080.
|
||||
|
||||
### Running the Main Monitoring Application
|
||||
|
||||
Before running the main monitoring application, ensure that the API server is running and the environment variables are set:
|
||||
|
||||
```sh
|
||||
export API_ADDRESS="http://localhost:8080"
|
||||
export GLITCHTIP_DSN="your-glitchtip-dsn"
|
||||
|
||||
oculus_main
|
||||
```
|
||||
|
||||
### Filtering Diff Outputs
|
||||
|
||||
To manually filter a diff output file, you can use the `filter` component:
|
||||
|
||||
```sh
|
||||
oculus_filter /path/to/diff/file "ignore_pattern1" "ignore_pattern2"
|
||||
```
|
||||
|
||||
## Docker Integration
|
||||
|
||||
You can integrate Oculus into your Docker setup by including the installation script in your Dockerfile. Below is an example Dockerfile:
|
||||
|
||||
```dockerfile
|
||||
FROM ubuntu:latest
|
||||
|
||||
# Install dependencies
|
||||
RUN apt-get update && apt-get install -y curl
|
||||
|
||||
# Download and run the Oculus install script
|
||||
RUN curl -sSL https://git.nixc.us/colin/Oculus/raw/branch/main/install.sh -o install.sh && \
|
||||
chmod +x install.sh && \
|
||||
./install.sh
|
||||
|
||||
# Set environment variables
|
||||
ENV API_ADDRESS="http://localhost:8080"
|
||||
ENV GLITCHTIP_DSN="your-glitchtip-dsn"
|
||||
|
||||
# Start the API server and the main application
|
||||
CMD ["sh", "-c", "oculus_api & oculus_main"]
|
||||
```
|
||||
|
||||
### Building the Docker Image
|
||||
|
||||
To build the Docker image, run:
|
||||
|
||||
```sh
|
||||
docker build -t oculus-toolchain .
|
||||
```
|
||||
|
||||
### Running the Docker Container
|
||||
|
||||
To run the Docker container, use:
|
||||
|
||||
```sh
|
||||
docker run -d --name oculus-toolchain oculus-toolchain
|
||||
```
|
|
@ -0,0 +1,115 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ContainerInfo struct {
|
||||
ID string
|
||||
Name string
|
||||
CName string
|
||||
Interval string
|
||||
Ignores []string
|
||||
}
|
||||
|
||||
func listContainersHandler(w http.ResponseWriter, r *http.Request) {
|
||||
containers, err := listContainers()
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Error listing containers: %v", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(containers); err != nil {
|
||||
http.Error(w, fmt.Sprintf("Error encoding response: %v", err), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func getDiffHandler(w http.ResponseWriter, r *http.Request) {
|
||||
containerID := r.URL.Query().Get("id")
|
||||
if containerID == "" {
|
||||
http.Error(w, "Missing container ID", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
diffOutput, err := getDiffOutput(containerID)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Error getting diff for container %s: %v", containerID, err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.Write([]byte(diffOutput))
|
||||
}
|
||||
|
||||
func startServer() {
|
||||
http.HandleFunc("/containers", listContainersHandler)
|
||||
http.HandleFunc("/diff", getDiffHandler)
|
||||
|
||||
log.Println("Starting server on :8080")
|
||||
if err := http.ListenAndServe(":8080", nil); err != nil {
|
||||
log.Fatalf("Error starting server: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func listContainers() ([]ContainerInfo, error) {
|
||||
output, err := exec.Command("docker", "ps", "--format", "{{.ID}} {{.Names}} {{.Label \"oculus.enable\"}} {{.Label \"oculus.interval\"}} {{.Label \"oculus.cname\"}} {{.Label \"oculus.ignores\"}}").Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lines := strings.Split(string(output), "\n")
|
||||
var containers []ContainerInfo
|
||||
|
||||
for _, line := range lines {
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 3 || parts[2] == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
id := parts[0]
|
||||
name := parts[1]
|
||||
interval := "300s"
|
||||
if len(parts) > 3 && parts[3] != "" {
|
||||
interval = parts[3]
|
||||
}
|
||||
|
||||
cname := name
|
||||
if len(parts) > 4 && parts[4] != "" {
|
||||
cname = parts[4]
|
||||
}
|
||||
|
||||
ignores := []string{}
|
||||
if len(parts) > 5 && parts[5] != "" {
|
||||
ignores = strings.Split(parts[5], ",")
|
||||
}
|
||||
|
||||
containers = append(containers, ContainerInfo{
|
||||
ID: id,
|
||||
Name: name,
|
||||
CName: cname,
|
||||
Interval: interval,
|
||||
Ignores: ignores,
|
||||
})
|
||||
}
|
||||
|
||||
return containers, nil
|
||||
}
|
||||
|
||||
func getDiffOutput(containerID string) (string, error) {
|
||||
cmd := exec.Command("docker", "diff", containerID)
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("docker diff failed: %w", err)
|
||||
}
|
||||
return string(output), nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
startServer()
|
||||
}
|
99
build.sh
99
build.sh
|
@ -1,70 +1,75 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Default architecture
|
||||
DEFAULT_ARCH="linux/amd64"
|
||||
ARCHITECTURES=("darwin/arm64" "linux/amd64" "linux/arm64" "darwin/amd64" "windows/amd64")
|
||||
PROJECT_NAME=$(basename "$(pwd)")
|
||||
|
||||
# Supported architectures (adjust as needed)
|
||||
ARCHITECTURES=("linux/amd64" "linux/arm64" "linux/arm/v7" "darwin/amd64" "darwin/arm64")
|
||||
|
||||
# Ensure all necessary directories exist and go modules are ready
|
||||
prepare_build() {
|
||||
# Create necessary directories if they don't exist
|
||||
mkdir -p dist
|
||||
mkdir -p build_logs
|
||||
|
||||
# Initialize go modules if go.mod does not exist
|
||||
mkdir -p dist build_logs
|
||||
if [ ! -f go.mod ]; then
|
||||
echo "Initializing Go modules"
|
||||
go mod init yourmodule # Replace 'yourmodule' with your actual module name or path
|
||||
go mod init "$PROJECT_NAME"
|
||||
fi
|
||||
|
||||
# Fetch and ensure all dependencies are up to date
|
||||
echo "Checking dependencies..."
|
||||
go mod tidy
|
||||
}
|
||||
|
||||
# Build function
|
||||
build_binary() {
|
||||
os=$1
|
||||
arch=$2
|
||||
output_name="oculus"
|
||||
local os=$1
|
||||
local arch=$2
|
||||
local output_main="dist/${PROJECT_NAME}_${os}_${arch}_main"
|
||||
local output_filter="dist/${PROJECT_NAME}_${os}_${arch}_filter"
|
||||
local output_api="dist/${PROJECT_NAME}_${os}_${arch}_api"
|
||||
|
||||
if [[ "$os/$arch" != "$DEFAULT_ARCH" ]]; then
|
||||
output_name="${output_name}_${os}_${arch}"
|
||||
env GOOS=$os GOARCH=$arch go build -o $output_main main.go &> "build_logs/${os}_${arch}_main.log"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Build failed for $os/$arch main" >> "build_logs/error.log"
|
||||
else
|
||||
echo "Build succeeded for $os/$arch main"
|
||||
fi
|
||||
|
||||
output_name="dist/${output_name}"
|
||||
|
||||
# Dynamic Linking
|
||||
echo "Building dynamically linked for ${os}/${arch} -> ${output_name}"
|
||||
GOOS=${os} GOARCH=${arch} go build -o ${output_name} main.go 2>build_logs/${os}_${arch}_build.log
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Successfully built ${output_name}"
|
||||
env GOOS=$os GOARCH=$arch go build -o $output_filter filter.go &> "build_logs/${os}_${arch}_filter.log"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Build failed for $os/$arch filter" >> "build_logs/error.log"
|
||||
else
|
||||
echo "Failed to build ${output_name}. Check build_logs/${os}_${arch}_build.log for errors."
|
||||
echo "Build succeeded for $os/$arch filter"
|
||||
fi
|
||||
|
||||
# Static Linking
|
||||
if [[ "$os" == "linux" ]]; then # Typically, static linking is most relevant for Linux environments
|
||||
static_output_name="${output_name}_static"
|
||||
echo "Building statically linked for ${os}/${arch} -> ${static_output_name}"
|
||||
CGO_ENABLED=0 GOOS=${os} GOARCH=${arch} go build -a -ldflags '-extldflags "-static"' -o ${static_output_name} main.go 2>build_logs/${os}_${arch}_static_build.log
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Successfully built ${static_output_name}"
|
||||
env GOOS=$os GOARCH=$arch go build -o $output_api api.go &> "build_logs/${os}_${arch}_api.log"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Build failed for $os/$arch api" >> "build_logs/error.log"
|
||||
else
|
||||
echo "Failed to build ${static_output_name}. Check build_logs/${os}_${arch}_static_build.log for errors."
|
||||
echo "Build succeeded for $os/$arch api"
|
||||
fi
|
||||
|
||||
if [ "$os" == "linux" ]; then
|
||||
env GOOS=$os GOARCH=$arch CGO_ENABLED=0 go build -a -ldflags '-extldflags "-static"' -o "${output_main}_static" main.go &> "build_logs/${os}_${arch}_main_static.log"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Static build failed for $os/$arch main" >> "build_logs/error.log"
|
||||
else
|
||||
echo "Static build succeeded for $os/$arch main"
|
||||
fi
|
||||
|
||||
env GOOS=$os GOARCH=$arch CGO_ENABLED=0 go build -a -ldflags '-extldflags "-static"' -o "${output_filter}_static" filter.go &> "build_logs/${os}_${arch}_filter_static.log"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Static build failed for $os/$arch filter" >> "build_logs/error.log"
|
||||
else
|
||||
echo "Static build succeeded for $os/$arch filter"
|
||||
fi
|
||||
|
||||
env GOOS=$os GOARCH=$arch CGO_ENABLED=0 go build -a -ldflags '-extldflags "-static"' -o "${output_api}_static" api.go &> "build_logs/${os}_${arch}_api_static.log"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Static build failed for $os/$arch api" >> "build_logs/error.log"
|
||||
else
|
||||
echo "Static build succeeded for $os/$arch api"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Main Build Process
|
||||
prepare_build
|
||||
for arch in "${ARCHITECTURES[@]}"; do
|
||||
IFS='/' read -r -a parts <<< "$arch" # Split architecture string
|
||||
os=${parts[0]}
|
||||
arch=${parts[1]}
|
||||
main() {
|
||||
prepare_build
|
||||
for arch in "${ARCHITECTURES[@]}"; do
|
||||
IFS="/" read -r os arch <<< "$arch"
|
||||
build_binary $os $arch
|
||||
done
|
||||
|
||||
echo "Build process completed."
|
||||
done
|
||||
echo "Build process completed."
|
||||
}
|
||||
|
||||
main
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
# command-line-arguments
|
||||
./main.go:9:5: "os" imported and not used
|
||||
./main.go:11:5: "strings" imported and not used
|
||||
./main.go:12:5: "time" imported and not used
|
||||
./main.go:15:5: "github.com/docker/docker/api/types/events" imported and not used
|
||||
./main.go:34:70: undefined: types.ContainerListOptions
|
|
@ -1,6 +0,0 @@
|
|||
# command-line-arguments
|
||||
./main.go:9:5: "os" imported and not used
|
||||
./main.go:11:5: "strings" imported and not used
|
||||
./main.go:12:5: "time" imported and not used
|
||||
./main.go:15:5: "github.com/docker/docker/api/types/events" imported and not used
|
||||
./main.go:34:70: undefined: types.ContainerListOptions
|
|
@ -1,6 +0,0 @@
|
|||
# command-line-arguments
|
||||
./main.go:9:5: "os" imported and not used
|
||||
./main.go:11:5: "strings" imported and not used
|
||||
./main.go:12:5: "time" imported and not used
|
||||
./main.go:15:5: "github.com/docker/docker/api/types/events" imported and not used
|
||||
./main.go:34:70: undefined: types.ContainerListOptions
|
|
@ -1,6 +0,0 @@
|
|||
# command-line-arguments
|
||||
./main.go:9:5: "os" imported and not used
|
||||
./main.go:11:5: "strings" imported and not used
|
||||
./main.go:12:5: "time" imported and not used
|
||||
./main.go:15:5: "github.com/docker/docker/api/types/events" imported and not used
|
||||
./main.go:34:70: undefined: types.ContainerListOptions
|
|
@ -1,6 +0,0 @@
|
|||
# command-line-arguments
|
||||
./main.go:9:5: "os" imported and not used
|
||||
./main.go:11:5: "strings" imported and not used
|
||||
./main.go:12:5: "time" imported and not used
|
||||
./main.go:15:5: "github.com/docker/docker/api/types/events" imported and not used
|
||||
./main.go:34:70: undefined: types.ContainerListOptions
|
|
@ -1,6 +0,0 @@
|
|||
# command-line-arguments
|
||||
./main.go:9:5: "os" imported and not used
|
||||
./main.go:11:5: "strings" imported and not used
|
||||
./main.go:12:5: "time" imported and not used
|
||||
./main.go:15:5: "github.com/docker/docker/api/types/events" imported and not used
|
||||
./main.go:34:70: undefined: types.ContainerListOptions
|
|
@ -1,6 +0,0 @@
|
|||
# command-line-arguments
|
||||
./main.go:9:5: "os" imported and not used
|
||||
./main.go:11:5: "strings" imported and not used
|
||||
./main.go:12:5: "time" imported and not used
|
||||
./main.go:15:5: "github.com/docker/docker/api/types/events" imported and not used
|
||||
./main.go:34:70: undefined: types.ContainerListOptions
|
|
@ -1,6 +0,0 @@
|
|||
# command-line-arguments
|
||||
./main.go:9:5: "os" imported and not used
|
||||
./main.go:11:5: "strings" imported and not used
|
||||
./main.go:12:5: "time" imported and not used
|
||||
./main.go:15:5: "github.com/docker/docker/api/types/events" imported and not used
|
||||
./main.go:34:70: undefined: types.ContainerListOptions
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,6 @@
|
|||
services:
|
||||
oculus:
|
||||
build:
|
||||
context: ./docker/oculus/
|
||||
dockerfile: Dockerfile.production
|
||||
image: git.nixc.us/colin/oculus:production
|
|
@ -0,0 +1,6 @@
|
|||
services:
|
||||
oculus:
|
||||
build:
|
||||
context: ./docker/oculus/
|
||||
dockerfile: Dockerfile
|
||||
image: git.nixc.us/colin/oculus:staging
|
|
@ -0,0 +1,9 @@
|
|||
FROM alpine:latest
|
||||
RUN apk update && apk add --no-cache curl bash
|
||||
RUN curl -sSL https://git.nixc.us/colin/Oculus/raw/branch/main/install.sh | bash
|
||||
RUN curl -sSL https://git.nixc.us/Nixius/go-glitch/raw/branch/master/install.sh | bash
|
||||
COPY notify.sh /notify.sh
|
||||
RUN chmod +x /notify.sh
|
||||
ENV GLITCHTIP_DSN=""
|
||||
CMD ["/usr/local/bin/oculus"]
|
||||
|
|
@ -0,0 +1 @@
|
|||
FROM git.nixc.us/colin/oculus:staging
|
|
@ -0,0 +1,105 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 3 {
|
||||
log.Fatalf("Usage: %s <file> <pattern1> [<pattern2> ... <patternN>]\n", os.Args[0])
|
||||
}
|
||||
|
||||
filename := os.Args[1]
|
||||
patterns := os.Args[2:]
|
||||
|
||||
// Compile patterns into regular expressions
|
||||
regexPatterns := compilePatterns(patterns)
|
||||
|
||||
// Read the file
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
log.Fatalf("Error opening file: %s\n", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var filteredLines []string
|
||||
var removedCount int
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
fmt.Printf("Processing line: %s\n", line) // Debug print
|
||||
if matchesAnyPattern(line, regexPatterns) {
|
||||
fmt.Printf("Line matches pattern, removing: %s\n", line) // Debug print
|
||||
removedCount++
|
||||
} else {
|
||||
filteredLines = append(filteredLines, line)
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Fatalf("Error reading file: %s\n", err)
|
||||
}
|
||||
|
||||
// Write the filtered lines back to the file
|
||||
tempFile, err := os.CreateTemp("", "filtered_output")
|
||||
if err != nil {
|
||||
log.Fatalf("Error creating temporary file: %s\n", err)
|
||||
}
|
||||
defer os.Remove(tempFile.Name())
|
||||
|
||||
for _, line := range filteredLines {
|
||||
_, err = tempFile.WriteString(line + "\n")
|
||||
if err != nil {
|
||||
log.Fatalf("Error writing to temporary file: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
tempFile.Close()
|
||||
|
||||
err = os.Rename(tempFile.Name(), filename)
|
||||
if err != nil {
|
||||
log.Fatalf("Error renaming temporary file: %s\n", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Filtered %d lines from %s\n", removedCount, filename)
|
||||
}
|
||||
|
||||
func compilePatterns(patterns []string) []*regexp.Regexp {
|
||||
var regexPatterns []*regexp.Regexp
|
||||
for _, pattern := range patterns {
|
||||
// Convert wildcard pattern to regex pattern
|
||||
regexPattern := strings.ReplaceAll(regexp.QuoteMeta(pattern), "\\*", ".*")
|
||||
regexPattern = strings.TrimSuffix(regexPattern, `\.`) // Remove trailing dot if present
|
||||
fmt.Printf("Compiled pattern: %s to regex: %s\n", pattern, regexPattern) // Debug print
|
||||
re, err := regexp.Compile(regexPattern)
|
||||
if err != nil {
|
||||
log.Fatalf("Error compiling regex pattern: %s\n", err)
|
||||
}
|
||||
regexPatterns = append(regexPatterns, re)
|
||||
}
|
||||
return regexPatterns
|
||||
}
|
||||
|
||||
func matchesAnyPattern(line string, patterns []*regexp.Regexp) bool {
|
||||
// Get the full path including directory
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) < 2 {
|
||||
return false
|
||||
}
|
||||
fullPath := parts[1]
|
||||
fmt.Printf("Checking filename: %s against patterns\n", fullPath) // Debug print
|
||||
|
||||
for _, pattern := range patterns {
|
||||
if pattern.MatchString(fullPath) {
|
||||
fmt.Printf("Pattern matched: %s in filename: %s\n", pattern.String(), fullPath) // Debug print
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
34
go.mod
34
go.mod
|
@ -1,35 +1,3 @@
|
|||
module yourmodule
|
||||
module oculus
|
||||
|
||||
go 1.21.1
|
||||
|
||||
require (
|
||||
github.com/docker/docker v26.1.4+incompatible
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
|
|
123
go.sum
123
go.sum
|
@ -1,123 +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/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/sirupsen/logrus v1.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=
|
38
install.sh
38
install.sh
|
@ -1,15 +1,11 @@
|
|||
#!/bin/bash
|
||||
|
||||
INSTALL_DIR="/usr/local/bin"
|
||||
BINARY_NAME="oculus"
|
||||
BASE_URL="https://git.nixc.us/colin/oculus/raw/branch/main/dist"
|
||||
PROJECT_NAME=$(basename "$(pwd)")
|
||||
BASE_URL="https://git.nixc.us/colin/Oculus/raw/branch/main/dist"
|
||||
|
||||
declare -A binaries
|
||||
binaries["linux/amd64"]="oculus_linux_amd64"
|
||||
binaries["linux/arm64"]="oculus_linux_arm64"
|
||||
binaries["linux/arm/v7"]="oculus_linux_arm"
|
||||
binaries["darwin/amd64"]="oculus_darwin_amd64"
|
||||
binaries["darwin/arm64"]="oculus_darwin_arm64"
|
||||
# Supported architectures
|
||||
ARCHITECTURES=("linux/amd64" "linux/arm64" "linux/arm/v7" "darwin/amd64" "darwin/arm64")
|
||||
|
||||
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
ARCH="$(uname -m)"
|
||||
|
@ -21,17 +17,21 @@ case $ARCH in
|
|||
*) echo "Unsupported architecture: $ARCH"; exit 1 ;;
|
||||
esac
|
||||
|
||||
KEY="${OS}/${ARCH}"
|
||||
COMPONENTS=("filter" "api" "main")
|
||||
|
||||
if [[ -z "${binaries[$KEY]}" ]]; then
|
||||
echo "No pre-built binary for your system architecture ($KEY)."
|
||||
exit 1
|
||||
fi
|
||||
for COMPONENT in "${COMPONENTS[@]}"; do
|
||||
BINARY_NAME="${PROJECT_NAME}_${COMPONENT}"
|
||||
BINARY_URL="${BASE_URL}/${PROJECT_NAME}_${OS}_${ARCH}_${COMPONENT}"
|
||||
echo "Downloading and installing $BINARY_NAME from $BINARY_URL..."
|
||||
|
||||
BINARY_URL="${BASE_URL}/${binaries[$KEY]}"
|
||||
# Check if we have write permission to the install directory
|
||||
if [ -w "${INSTALL_DIR}" ]; then
|
||||
curl -sSL "$BINARY_URL" -o "${INSTALL_DIR}/${BINARY_NAME}"
|
||||
chmod +x "${INSTALL_DIR}/${BINARY_NAME}"
|
||||
else
|
||||
sudo curl -sSL "$BINARY_URL" -o "${INSTALL_DIR}/${BINARY_NAME}"
|
||||
sudo chmod +x "${INSTALL_DIR}/${BINARY_NAME}"
|
||||
fi
|
||||
|
||||
echo "Downloading and installing $BINARY_NAME from $BINARY_URL..."
|
||||
sudo curl -sSL "$BINARY_URL" -o "${INSTALL_DIR}/${BINARY_NAME}"
|
||||
|
||||
sudo chmod +x "${INSTALL_DIR}/${BINARY_NAME}"
|
||||
echo "Installed $BINARY_NAME to $INSTALL_DIR"
|
||||
echo "Installed $BINARY_NAME to $INSTALL_DIR"
|
||||
done
|
||||
|
|
341
main.go
341
main.go
|
@ -1,182 +1,255 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
const (
|
||||
notifyScript = "/notify.sh"
|
||||
)
|
||||
|
||||
// ContainerDiff represents the state of a container
|
||||
type ContainerDiff struct {
|
||||
type ContainerInfo struct {
|
||||
ID string
|
||||
Image string
|
||||
Labels map[string]string
|
||||
Name string
|
||||
CName string
|
||||
Interval string
|
||||
Ignores []string
|
||||
}
|
||||
|
||||
// getRunningContainers fetches the list of running containers with relevant labels
|
||||
func getRunningContainers(cli *client.Client) ([]ContainerDiff, error) {
|
||||
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
|
||||
type MonitoredContainer struct {
|
||||
Info ContainerInfo
|
||||
LastChecked time.Time
|
||||
}
|
||||
|
||||
var (
|
||||
apiAddress string
|
||||
glitchtipDSN string
|
||||
notifiedChanges = make(map[string]string)
|
||||
monitoredContainers = make(map[string]*MonitoredContainer)
|
||||
mu sync.Mutex
|
||||
)
|
||||
|
||||
func init() {
|
||||
apiAddress = os.Getenv("API_ADDRESS")
|
||||
if apiAddress == "" {
|
||||
apiAddress = "http://localhost:8080"
|
||||
}
|
||||
|
||||
glitchtipDSN = os.Getenv("GLITCHTIP_DSN")
|
||||
if glitchtipDSN == "" {
|
||||
log.Fatal("GLITCHTIP_DSN environment variable is not set")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
log.Println("Starting Oculus...")
|
||||
|
||||
// Ensure the diffs directory exists
|
||||
err := os.MkdirAll("./diffs", os.ModePerm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
log.Fatalf("Error creating diffs directory: %v", err)
|
||||
}
|
||||
|
||||
var diffs []ContainerDiff
|
||||
for _, container := range containers {
|
||||
if _, ok := container.Labels["oculus.containerid"]; ok {
|
||||
diffs = append(diffs, ContainerDiff{
|
||||
ID: container.ID,
|
||||
Image: container.Image,
|
||||
Labels: container.Labels,
|
||||
})
|
||||
}
|
||||
for {
|
||||
err := fetchAndMonitorContainers()
|
||||
if err != nil {
|
||||
log.Printf("Error in fetching and monitoring containers: %v", err)
|
||||
}
|
||||
|
||||
return diffs, nil
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
// saveDiffs writes the container diffs to a file
|
||||
func saveDiffs(diffs []ContainerDiff, filePath string) error {
|
||||
data, err := json.Marshal(diffs)
|
||||
func fetchAndMonitorContainers() error {
|
||||
containers, err := fetchContainers()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(filePath, data, 0644)
|
||||
}
|
||||
|
||||
// loadDiffs reads the container diffs from a file
|
||||
func loadDiffs(filePath string) ([]ContainerDiff, error) {
|
||||
data, err := ioutil.ReadFile(filePath)
|
||||
for _, container := range containers {
|
||||
mu.Lock()
|
||||
if _, exists := monitoredContainers[container.ID]; !exists {
|
||||
interval, err := time.ParseDuration(container.Interval)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var diffs []ContainerDiff
|
||||
err = json.Unmarshal(data, &diffs)
|
||||
return diffs, err
|
||||
}
|
||||
|
||||
// profileContainers logs the current state of containers to a file
|
||||
func profileContainers(cli *client.Client) {
|
||||
diffs, err := getRunningContainers(cli)
|
||||
if err != nil {
|
||||
log.Fatalf("Error profiling containers: %v", err)
|
||||
}
|
||||
|
||||
for _, diff := range diffs {
|
||||
if diff.Labels["oculus.mode"] == "profile" {
|
||||
filePath := fmt.Sprintf("%s.json", diff.Labels["oculus.containerid"])
|
||||
err := saveDiffs([]ContainerDiff{diff}, filePath)
|
||||
if err != nil {
|
||||
log.Fatalf("Error saving diffs: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("Profiled current containers and saved to file")
|
||||
}
|
||||
|
||||
// compareContainers compares the current state of containers with the saved state
|
||||
func compareContainers(cli *client.Client) {
|
||||
currentDiffs, err := getRunningContainers(cli)
|
||||
if err != nil {
|
||||
log.Fatalf("Error getting current containers: %v", err)
|
||||
}
|
||||
|
||||
for _, current := range currentDiffs {
|
||||
if current.Labels["oculus.mode"] == "monitor" {
|
||||
filePath := fmt.Sprintf("%s.json", current.Labels["oculus.containerid"])
|
||||
savedDiffs, err := loadDiffs(filePath)
|
||||
if err != nil {
|
||||
log.Printf("Error loading saved diffs for %s: %v", current.ID, err)
|
||||
log.Printf("Invalid interval for container %s (%s): %v", container.Name, container.ID, err)
|
||||
mu.Unlock()
|
||||
continue
|
||||
}
|
||||
|
||||
if len(savedDiffs) > 0 {
|
||||
saved := savedDiffs[0]
|
||||
if current.Image != saved.Image {
|
||||
log.Printf("Container %s changed: Image %s -> %s", current.ID, saved.Image, current.Image)
|
||||
runNotifyScript(current.ID, current.Image, saved.Image)
|
||||
}
|
||||
if current.Labels["oculus.ignorelist"] != saved.Labels["oculus.ignorelist"] {
|
||||
log.Printf("Container %s ignore list changed: %s -> %s", current.ID, saved.Labels["oculus.ignorelist"], current.Labels["oculus.ignorelist"])
|
||||
runNotifyScript(current.ID, current.Image, saved.Image)
|
||||
}
|
||||
} else {
|
||||
log.Printf("New container detected: ID %s, Image %s", current.ID, current.Image)
|
||||
runNotifyScript(current.ID, current.Image, "")
|
||||
monitoredContainers[container.ID] = &MonitoredContainer{
|
||||
Info: container,
|
||||
LastChecked: time.Now().Add(-interval),
|
||||
}
|
||||
}
|
||||
mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// runNotifyScript executes the notification script with the container details
|
||||
func runNotifyScript(containerID, newImage, oldImage string) {
|
||||
cmd := exec.Command(notifyScript, containerID, newImage, oldImage)
|
||||
err := cmd.Run()
|
||||
var wg sync.WaitGroup
|
||||
for _, monitoredContainer := range monitoredContainers {
|
||||
wg.Add(1)
|
||||
go func(mc *MonitoredContainer) {
|
||||
defer wg.Done()
|
||||
interval, err := time.ParseDuration(mc.Info.Interval)
|
||||
if err != nil {
|
||||
log.Printf("Error running notify script: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// watchDockerEvents listens for Docker events and triggers comparisons
|
||||
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)
|
||||
case err := <-errs:
|
||||
log.Printf("Error watching Docker events: %v", err)
|
||||
log.Printf("Invalid interval for container %s (%s): %v", mc.Info.Name, mc.Info.ID, err)
|
||||
return
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
if time.Since(mc.LastChecked) >= interval {
|
||||
mc.LastChecked = time.Now()
|
||||
mu.Unlock()
|
||||
checkAndNotify(mc.Info)
|
||||
} else {
|
||||
mu.Unlock()
|
||||
}
|
||||
}(monitoredContainer)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func fetchContainers() ([]ContainerInfo, error) {
|
||||
resp, err := http.Get(fmt.Sprintf("%s/containers", apiAddress))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("error fetching containers: %s", resp.Status)
|
||||
}
|
||||
|
||||
var containers []ContainerInfo
|
||||
if err := json.NewDecoder(resp.Body).Decode(&containers); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return containers, nil
|
||||
}
|
||||
|
||||
func fetchDiffOutput(containerID string) (string, error) {
|
||||
resp, err := http.Get(fmt.Sprintf("%s/diff?id=%s", apiAddress, containerID))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", fmt.Errorf("error fetching diff: %s", resp.Status)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(body), nil
|
||||
}
|
||||
|
||||
func checkAndNotify(container ContainerInfo) {
|
||||
diffOutput, err := fetchDiffOutput(container.ID)
|
||||
if err != nil {
|
||||
log.Printf("Error getting diffs for container %s (%s): %v", container.Name, container.ID, err)
|
||||
return
|
||||
}
|
||||
|
||||
filteredOutput, err := filterDiffOutput(diffOutput, container.CName, container.Ignores)
|
||||
if err != nil {
|
||||
log.Printf("Error filtering diffs for container %s (%s): %v", container.Name, container.ID, err)
|
||||
return
|
||||
}
|
||||
log.Printf("Filtered diff output for container %s: %s", container.Name, filteredOutput)
|
||||
|
||||
if filteredOutput != "" {
|
||||
diffHash := fmt.Sprintf("%x", md5.Sum([]byte(filteredOutput)))
|
||||
log.Printf("Diff hash for container %s: %s", container.Name, diffHash)
|
||||
|
||||
mu.Lock()
|
||||
lastNotifiedHash, notified := notifiedChanges[container.ID]
|
||||
mu.Unlock()
|
||||
|
||||
if !notified || lastNotifiedHash != diffHash {
|
||||
filename := filepath.Join("diffs", fmt.Sprintf("%s.diff", container.CName))
|
||||
err := writeToFile(filename, filteredOutput)
|
||||
if err != nil {
|
||||
log.Printf("Error writing diff to file: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
err = sendNotification(filteredOutput)
|
||||
if err != nil {
|
||||
log.Printf("Error sending notification for container %s: %v", container.ID, err)
|
||||
} else {
|
||||
mu.Lock()
|
||||
notifiedChanges[container.ID] = diffHash
|
||||
mu.Unlock()
|
||||
log.Printf("Notification sent and hash updated for container: %s (%s)", container.Name, container.ID)
|
||||
}
|
||||
} else {
|
||||
log.Printf("No new changes detected for container: %s (%s)", container.Name, container.ID)
|
||||
}
|
||||
} else {
|
||||
log.Printf("No significant changes detected for container: %s (%s)", container.Name, container.ID)
|
||||
}
|
||||
}
|
||||
|
||||
// scheduler sets up the cron jobs for profiling
|
||||
func scheduler(cli *client.Client) {
|
||||
c := cron.New()
|
||||
c.AddFunc("@every 1h", func() { profileContainers(cli) })
|
||||
c.Start()
|
||||
}
|
||||
func filterDiffOutput(diffOutput, cname string, ignores []string) (string, error) {
|
||||
filename := filepath.Join("diffs", fmt.Sprintf("%s.diff", cname))
|
||||
|
||||
func main() {
|
||||
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||
if (err != nil) {
|
||||
log.Fatalf("Error creating Docker client: %v", err)
|
||||
// Write the diff output to the file
|
||||
err := ioutil.WriteFile(filename, []byte(diffOutput), 0644)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error writing diff to file: %s", err)
|
||||
}
|
||||
|
||||
go scheduler(cli)
|
||||
// Construct the filter command
|
||||
args := append([]string{filename}, ignores...)
|
||||
cmd := exec.Command("filter", args...)
|
||||
fullCommand := fmt.Sprintf("filter %s", strings.Join(cmd.Args, " "))
|
||||
log.Printf("Running command: %s", fullCommand)
|
||||
fmt.Printf("Running command: %s\n", fullCommand) // Print the command to stdout for debugging
|
||||
|
||||
go watchDockerEvents(cli)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error running filter command: %s, output: %s", err, output)
|
||||
}
|
||||
|
||||
// Keep the program running
|
||||
select {}
|
||||
// Read the filtered output
|
||||
filteredOutput, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error reading filtered diff file: %s", err)
|
||||
}
|
||||
|
||||
return string(filteredOutput), nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func sendNotification(content string) error {
|
||||
cmd := exec.Command("go-glitch")
|
||||
cmd.Stdin = strings.NewReader(content)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
log.Printf("go-glitch output: %s", output)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
A /file1.txt
|
||||
A /file2.txt
|
||||
A /file3.txt
|
|
@ -0,0 +1,25 @@
|
|||
services:
|
||||
oculus:
|
||||
image: git.nixc.us/colin/oculus:production
|
||||
environment:
|
||||
GLITCHTIP_DSN: ""
|
||||
volumes:
|
||||
- /mnt/tank/persist/nixc.us/oculus/production/data:/log
|
||||
- "/var/run/docker.sock:/var/run/docker.sock:ro"
|
||||
deploy:
|
||||
placement:
|
||||
constraints:
|
||||
- node.role == manager
|
||||
labels:
|
||||
traefik.enable: "false"
|
||||
oculus.containerid: "oculus"
|
||||
oculus.ignorelist: "/log/,/tmp/"
|
||||
oculus.mode: "monitor"
|
||||
oculus.interval: "60s"
|
||||
update_config:
|
||||
order: stop-first
|
||||
failure_action: rollback
|
||||
delay: 0s
|
||||
parallelism: 1
|
||||
restart_policy:
|
||||
condition: on-failure
|
|
@ -0,0 +1,20 @@
|
|||
services:
|
||||
oculus:
|
||||
image: git.nixc.us/colin/oculus:staging
|
||||
environment:
|
||||
GLITCHTIP_DSN: ""
|
||||
# volumes:
|
||||
# - /mnt/tank/persist/nixc.us/oculus/staging/data:/log
|
||||
deploy:
|
||||
# placement:
|
||||
# constraints:
|
||||
# - node.hostname == macmini14
|
||||
labels:
|
||||
traefik.enable: "false"
|
||||
update_config:
|
||||
order: stop-first
|
||||
failure_action: rollback
|
||||
delay: 0s
|
||||
parallelism: 1
|
||||
restart_policy:
|
||||
condition: on-failure
|
Loading…
Reference in New Issue