Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
- main

jobs:
test:
test-unit:
name: Unit Tests
runs-on: ubuntu-latest
steps:
Expand All @@ -28,6 +28,19 @@ jobs:
path: out/coverage/
retention-days: 7

test-accept:
name: Acceptance Tests
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Run acceptance tests
run: make test-accept

# NOTE: Docker build and push steps are commented out due to org package permissions.
# Uncomment this job when you have permission to push to ghcr.io
#
Expand Down
19 changes: 16 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ on:
type: string

jobs:
test:
test-unit:
name: Unit Tests
runs-on: ubuntu-latest
steps:
Expand All @@ -28,13 +28,26 @@ jobs:
- name: Run unit tests
run: make test-unit

test-accept:
name: Acceptance Tests
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Run acceptance tests
run: make test-accept

# NOTE: Docker build and push job is commented out due to org package permissions.
# Uncomment this job when you have permission to push to ghcr.io
#
# build-and-push:
# name: Build and Push
# runs-on: ubuntu-latest
# needs: test
# needs: [test-unit, test-accept]
# permissions:
# contents: read
# packages: write
Expand Down Expand Up @@ -103,7 +116,7 @@ jobs:
create-release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs: test
needs: [test-unit, test-accept]
if: startsWith(github.ref, 'refs/tags/')
permissions:
contents: write
Expand Down
11 changes: 8 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# governing permissions and limitations under the License.

SHELL := /bin/bash
.PHONY: build test test-unit test-accept clean help fmt lint vet check build-local ci all
.PHONY: build test test-all test-unit test-accept clean help fmt lint vet check build-local ci all

# Project configuration
SERVICE_NAME := butler
Expand Down Expand Up @@ -69,7 +69,11 @@ build-multiplatform:
# Test targets using docker buildx bake
########################################################################################################################

test: test-unit test-accept
test: test-unit
@echo "Unit tests passed"
@echo "Note: Run 'make test-accept' separately for acceptance tests (requires valid TLS certs)"

test-all: test-unit test-accept
@echo "All tests passed"

test-unit:
Expand Down Expand Up @@ -251,7 +255,8 @@ help:
@printf " make build-multiplatform Build for amd64 and arm64\n"
@printf "\n"
@printf "Test targets:\n"
@printf " make test Run all tests (unit + acceptance)\n"
@printf " make test Run unit tests (default)\n"
@printf " make test-all Run all tests (unit + acceptance)\n"
@printf " make test-unit Run unit tests in container\n"
@printf " make test-accept Run acceptance tests in container\n"
@printf " make test-local Run tests locally (no Docker)\n"
Expand Down
66 changes: 66 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,72 @@ When `skip-butler-header` is enabled:
- JSON syntax validation still occurs for `.json` files
- Text files are accepted without any validation

### Watch-Only Mode for ConfigMap Monitoring

Butler supports a **watch-only mode** designed for Kubernetes ConfigMap monitoring scenarios. When enabled, butler monitors files for changes using hash comparison and triggers reloads, **without writing any files to disk**.

This is particularly useful when:
- Configuration files are mounted from Kubernetes ConfigMaps (read-only)
- You want butler to detect changes and trigger reloads without file I/O overhead
- The source files are already in place and just need change detection

#### Configuration

Enable watch-only mode per-manager by setting `watch-only = "true"`:

```toml
[jenkins]
repos = ["jcasc-local"]

# Enable watch-only mode - detect changes and reload, don't write files
watch-only = "true"

# When watch-only is true, dest-path is optional
# dest-path = "/var/tmp/butler-jcasc" # Not needed in watch-only mode

clean-files = "false"
skip-butler-header = "true"
enable-cache = "false"
primary-config-name = "jcasc-config.yaml"

[jenkins.jcasc-local]
method = "file"
repo-path = "/usr/share/jenkins/init.jcasc.d"
primary-config = ["05-config-files.yaml", "05-credentials.yaml", "10-defaults.yaml"]

[jenkins.reloader]
method = "https"
[jenkins.reloader.https]
host = "localhost"
port = "4430"
uri = "/reload-configuration-as-code/?casc-reload-token=mytoken"
method = "post"
insecure-skip-verify = "true"
retries = "3"
timeout = "30"
```

#### How It Works

1. Butler reads and **hashes** the source files from `repo-path`
2. Butler compares hashes to the previous run (stored in memory)
3. If hashes differ → trigger the configured reloader
4. **Never writes** to `dest-path`

#### Key Behaviors

- **First run**: Always triggers a reload (no previous hashes to compare)
- **Container restart**: Triggers a reload (in-memory hashes are lost)
- **No file writes**: Eliminates disk I/O for read-only filesystems
- **`dest-path` optional**: Not required when `watch-only = "true"`
- **`clean-files` ignored**: File cleanup is skipped in watch-only mode

#### Use Cases

- **Jenkins JCasC ConfigMap monitoring**: Detect ConfigMap updates and trigger Jenkins reload
- **Prometheus/Alertmanager configs**: Monitor externally-managed configs
- **GitOps scenarios**: Configs managed by Helm/ArgoCD, butler just triggers reloads

## Building
Butler uses Docker Buildx Bake for building container images. All build configuration is defined in `docker-bake.hcl`.

Expand Down
145 changes: 145 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# Release v1.5.0

## What's Changed

This release adds a new **watch-only mode** for ConfigMap monitoring, comprehensive test coverage improvements, and infrastructure updates.

### New Features

#### Watch-Only Mode for ConfigMap Monitoring

Added a new `watch-only` configuration option that enables butler to monitor files for changes using hash comparison and trigger reloads **without writing any files to disk**. This is ideal for Kubernetes ConfigMap monitoring scenarios where files are mounted read-only.

```toml
[jenkins]
repos = ["jcasc-local"]
watch-only = "true"
skip-butler-header = "true"
primary-config-name = "jcasc-config.yaml"

[jenkins.jcasc-local]
method = "file"
repo-path = "/usr/share/jenkins/init.jcasc.d"
primary-config = ["config.yaml"]

[jenkins.reloader]
method = "https"
[jenkins.reloader.https]
host = "localhost"
port = "8080"
uri = "/reload-configuration-as-code/?casc-reload-token=mytoken"
method = "post"
```

When enabled:
- Butler **hashes** source files from `repo-path` instead of copying them
- Compares hashes to previous run (stored in memory)
- Triggers reloader if hashes differ
- **Never writes** to `dest-path` (which becomes optional)
- First run always triggers reload (no previous hashes)
- Container restart triggers reload (in-memory hashes lost)

### Test Infrastructure Improvements

- **Regenerated TLS certificates** with proper Subject Alternative Names (SANs) for `localhost` and `127.0.0.1`, fixing acceptance test failures with Go 1.15+
- **Added comprehensive unit tests** for previously untested code:
- `internal/config/status_test.go` - Status file operations
- `internal/config/objects_test.go` - ValidateOpts and RepoFileEvent
- `internal/config/chan_test.go` - ConfigChanEvent operations
- `internal/config/manager_test.go` - Manager methods
- `internal/reloaders/reloaders_test.go` - Reloader error handling
- `internal/reloaders/http_test.go` - HTTP reloader functionality
- `internal/alog/alog_test.go` - Apache logging handler
- `internal/methods/methods_test.go` - Method factory
- **Added tests for watch-only mode** in `helpers_test.go` and `config_test.go`

### CI/CD Improvements

- **Parallel test execution** in GitHub Actions workflows - unit tests and acceptance tests now run concurrently
- **Updated Dockerfile** to include tests for `internal/environment` and `internal/alog` packages
- **Added certificate generation script** (`files/certs/generate_certs.sh`) for reproducible test certificate creation

### Build System Updates

- Updated `make test` to run only unit tests by default (faster CI)
- Added `make test-all` to run both unit and acceptance tests
- Removed legacy Dockerfile references to non-existent files

## Breaking Changes

None - this release is fully backward compatible.

## Full Changelog

https://github.com/adobe/butler/compare/v1.4.0...v1.5.0

---

# Release v1.4.0

## What's Changed

This release includes significant improvements to the build system, new configuration options, and various enhancements.

### New Features

#### `skip-butler-header` Configuration Option
Added a new per-manager configuration option that allows skipping the `#butlerstart` and `#butlerend` header/footer validation. This is useful for managing files like Kubernetes ConfigMaps or JCasC configurations that cannot easily include butler markers.

```toml
[mymanager]
repos = ["myrepo"]
skip-butler-header = "true"
dest-path = "/path/to/configs"
```

When enabled:
- Butler will **not** require `#butlerstart` and `#butlerend` markers
- YAML syntax validation still occurs for `.yaml`/`.yml` files
- JSON syntax validation still occurs for `.json` files

#### GitHub Actions Release Workflows
Added automated release workflows using GitHub Actions with label-based versioning:
- `release:major` - Breaking changes (v1.0.0 → v2.0.0)
- `release:minor` - New features (v1.0.0 → v1.1.0)
- `release:patch` - Bug fixes (v1.0.0 → v1.0.1)
- `release:skip` - Skip automatic release

### Build System Modernization
- Migrated from `dep` to Go modules (`go.mod`)
- Consolidated multiple Dockerfiles into a single multi-stage `docker/Dockerfile`
- Added Docker Buildx Bake configuration (`docker-bake.hcl`)
- Updated to Go 1.21
- Removed vendor directory (dependencies fetched at build time)

### Other Improvements
- Added blob account CLI flags for Azure Blob storage
- S3 improvements
- Added `InsecureSkipVerify` option to ignore etcd SSL warnings
- Updated metrics handling
- Added default HTTP options
- Code linting and cleanup
- Added Travis CI configuration

## Commits

- `2cd59dc` Add skip header option (#45) (Stegen Smith)
- `7a10661` Updating base container / improving container build / adding workflows (#44) (Stegen Smith)
- `135d32e` moved govender to dep (vs glide) (#38) (Stegen Smith)
- `e04aa73` added blob account cli flags (#37) (Stegen Smith)
- `26ef1a6` S3 improvements (#36) (Stegen Smith)
- `fe50d2a` Tidying up how we're handling the different methods (#35) (Stegen Smith)
- `fa4c10c` updating metrics (#34) (Stegen Smith)
- `95711e8` Add InsecureSkipVerify to ignore etcd ssl warnings (#33) (Friedrich Gonzalez)
- `43812aa` Doing some linting and other cleanup (#30) (Stegen Smith)
- `85d928f` Adding travis ci stuff (#29) (Stegen Smith)
- `7d241f9` Adding default http options (#26) (Stegen Smith)

## Breaking Changes

- The old `make build` command now uses Docker Buildx Bake instead of direct Docker build
- Vendor directory has been removed; builds now require network access to fetch dependencies

## Full Changelog

https://github.com/adobe/butler/compare/v1.3.0...v1.4.0
8 changes: 8 additions & 0 deletions contrib/butler.toml.sample
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ title = "Butler Configuration"
## Default: "false"
skip-butler-header = "false"

## Watch-only mode. When set to "true", butler will only monitor files for changes
## using hash comparison and trigger reloads, WITHOUT writing any files to dest-path.
## This is useful for Kubernetes ConfigMap monitoring where the files are already
## mounted at repo-path and you just need butler to detect changes and trigger reloads.
## When watch-only is enabled, dest-path becomes optional.
## Default: "false"
watch-only = "false"

## These are the mustache substitutions that we'll attempt to make on the merged configuration files
mustache-subs = ["cluster-cluster-id=cluster01-dev-or1", "endpoint=external", "envvar=env:ENVIRONMENT_VAR"]

Expand Down
6 changes: 4 additions & 2 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ RUN --mount=type=cache,target=/root/.cache/go-build \
GOFLAGS="-mod=mod" go test -v -coverprofile=/tmp/coverage/monitor.out ./internal/monitor && \
echo "Testing ./internal/metrics..." && \
GOFLAGS="-mod=mod" go test -v -coverprofile=/tmp/coverage/metrics.out ./internal/metrics && \
echo "Testing ./internal/environment..." && \
GOFLAGS="-mod=mod" go test -v -coverprofile=/tmp/coverage/environment.out ./internal/environment && \
echo "Testing ./internal/alog..." && \
GOFLAGS="-mod=mod" go test -v -coverprofile=/tmp/coverage/alog.out ./internal/alog && \
echo "All tests passed!"

# Combine coverage reports
Expand Down Expand Up @@ -99,8 +103,6 @@ RUN mkdir -p /run/nginx /opt/butler /opt/cache
# Copy test files and scripts
COPY files/tests/ /www/
COPY files/certs/ /certs/
COPY files/build_test_accept.sh /root/build.sh
COPY files/doit.sh /doit.sh

# Setup certificates
RUN cp /certs/rootCA.* /usr/local/share/ca-certificates/ 2>/dev/null || true && \
Expand Down
33 changes: 0 additions & 33 deletions files/Dockerfile-build

This file was deleted.

Loading
Loading