diff --git a/.github/workflows/callable-build.yaml b/.github/workflows/callable-build.yaml index 16346f5..ee3ce6d 100644 --- a/.github/workflows/callable-build.yaml +++ b/.github/workflows/callable-build.yaml @@ -60,7 +60,7 @@ jobs: exit 1 fi - go-build: + kerberos: runs-on: ubuntu-latest steps: - name: Checkout @@ -104,3 +104,138 @@ jobs: - name: Build run: make build + + echo: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Set up Golang + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + with: + go-version-file: go.mod + cache: false + + - name: Compute build cache key + id: build-cache-key + run: | + checksum=$( + { + cat go.mod + [ -f go.sum ] && cat go.sum + cat Makefile + find . -type f -name '*.go' \ + -not -path './test/suites/*' \ + -not -path './tools/*' \ + -print0 | sort -z | xargs -0 cat + } | md5sum | awk '{print $1}' + ) + echo "checksum=$checksum" >> "$GITHUB_OUTPUT" + + - name: Cache Go module cache + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/go/pkg/mod + key: echo-go-mod-${{ runner.os }}-${{ hashFiles('go.sum') }} + + - name: Cache Go build cache + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/.cache/go-build + key: echo-go-build-${{ runner.os }}-${{ steps.build-cache-key.outputs.checksum }} + restore-keys: | + echo-go-build-${{ runner.os }}- + + - name: Build + run: make echo/build + + connector: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Set up Golang + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + with: + go-version-file: go.mod + cache: false + + - name: Compute build cache key + id: build-cache-key + run: | + checksum=$( + { + cat go.mod + [ -f go.sum ] && cat go.sum + cat Makefile + find . -type f -name '*.go' \ + -not -path './test/suites/*' \ + -not -path './tools/*' \ + -print0 | sort -z | xargs -0 cat + } | md5sum | awk '{print $1}' + ) + echo "checksum=$checksum" >> "$GITHUB_OUTPUT" + + - name: Cache Go module cache + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/go/pkg/mod + key: connector-go-mod-${{ runner.os }}-${{ hashFiles('go.sum') }} + + - name: Cache Go build cache + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/.cache/go-build + key: connector-go-build-${{ runner.os }}-${{ steps.build-cache-key.outputs.checksum }} + restore-keys: | + connector-go-build-${{ runner.os }}- + + - name: Build + run: make connector/build + + krbctl: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Set up Golang + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + with: + go-version-file: go.mod + cache: false + + - name: Compute build cache key + id: build-cache-key + run: | + checksum=$( + { + cat go.mod + [ -f go.sum ] && cat go.sum + cat Makefile + find . -type f -name '*.go' \ + -not -path './test/suites/*' \ + -not -path './tools/*' \ + -print0 | sort -z | xargs -0 cat + } | md5sum | awk '{print $1}' + ) + echo "checksum=$checksum" >> "$GITHUB_OUTPUT" + + - name: Cache Go module cache + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/go/pkg/mod + key: krbctl-go-mod-${{ runner.os }}-${{ hashFiles('go.sum') }} + + - name: Cache Go build cache + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/.cache/go-build + key: krbctl-go-build-${{ runner.os }}-${{ steps.build-cache-key.outputs.checksum }} + restore-keys: | + krbctl-go-build-${{ runner.os }}- + + - name: Build + run: make krbctl/build diff --git a/.github/workflows/release-krbctl.yaml b/.github/workflows/release-krbctl.yaml new file mode 100644 index 0000000..4736e6d --- /dev/null +++ b/.github/workflows/release-krbctl.yaml @@ -0,0 +1,71 @@ +name: Release krbctl + +on: + release: + types: + - published + +concurrency: + group: release-cli-${{ github.ref_name }} + cancel-in-progress: false + +permissions: + contents: read + +jobs: + release-assets: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Set up Golang + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + with: + go-version-file: go.mod + cache: false + + - name: Compute build cache key + id: build-cache-key + run: | + checksum=$( + { + cat go.mod + [ -f go.sum ] && cat go.sum + cat Makefile + find . -type f -name '*.go' \ + -not -path './test/suites/*' \ + -not -path './tools/*' \ + -print0 | sort -z | xargs -0 cat + } | md5sum | awk '{print $1}' + ) + echo "checksum=$checksum" >> "$GITHUB_OUTPUT" + + - name: Cache Go module cache + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/go/pkg/mod + key: cli-release-go-mod-${{ runner.os }}-${{ hashFiles('go.sum') }} + + - name: Cache Go build cache + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/.cache/go-build + key: krbctl-release-go-build-${{ runner.os }}-${{ steps.build-cache-key.outputs.checksum }} + restore-keys: | + krbctl-release-go-build-${{ runner.os }}- + + - name: Build release artifacts + run: make krbctl/release VERSION=${{ github.ref_name }} + + - name: Upload artifacts to release + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release upload "${{ github.ref_name }}" \ + build/release/*.tar.gz \ + build/release/*.zip \ + build/release/checksums.txt \ + --clobber diff --git a/Makefile b/Makefile index ccd39cb..660eb49 100644 --- a/Makefile +++ b/Makefile @@ -228,6 +228,7 @@ docker/network/rm: echo/build: $(call cecho,Building Echo binary...,$(BOLD_YELLOW)) + @mkdir -p build @CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o build/echo ./cmd/echo echo/docker/build: @@ -310,6 +311,55 @@ connector/docker/stop: connector/docker/rm: @docker rm connector || true +# krbctl version injection: the version string is compiled into the binary via +# ldflags, since krbctl is a distributed CLI and end users won't set env vars. +KRBCTL_PKG := github.com/trebent/kerberos/cmd/krbctl/cmd +KRBCTL_LDFLAGS := -s -w -X $(KRBCTL_PKG).version=$(VERSION) + +# krbctl release build matrix (GOOS/GOARCH pairs). +KRBCTL_PLATFORMS := \ + linux/amd64 \ + linux/arm64 \ + darwin/amd64 \ + darwin/arm64 \ + windows/amd64 \ + windows/arm64 + +krbctl/build: + $(call cecho,Building krbctl binary...,$(BOLD_YELLOW)) + @mkdir -p build + @CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="$(KRBCTL_LDFLAGS)" -o build/krbctl ./cmd/krbctl + +krbctl/install: + $(call cecho,Installing krbctl binary to $(GOBIN)...,$(BOLD_YELLOW)) + @CGO_ENABLED=0 GOOS=linux go install -trimpath -ldflags="$(KRBCTL_LDFLAGS)" ./cmd/krbctl + +krbctl/release: + $(call cecho,Building krbctl release artifacts for version $(VERSION)...,$(BOLD_YELLOW)) + @rm -rf build/release + @mkdir -p build/release + @for platform in $(KRBCTL_PLATFORMS); do \ + os=$${platform%/*}; \ + arch=$${platform#*/}; \ + name=krbctl_$(VERSION)_$${os}_$${arch}; \ + bin=krbctl; \ + if [ "$${os}" = "windows" ]; then bin=krbctl.exe; fi; \ + printf "${BOLD_YELLOW} -> $${os}/$${arch}${RESET}\n"; \ + mkdir -p build/release/$${name}; \ + CGO_ENABLED=0 GOOS=$${os} GOARCH=$${arch} \ + go build -trimpath -ldflags="$(KRBCTL_LDFLAGS)" \ + -o build/release/$${name}/$${bin} ./cmd/krbctl || exit 1; \ + if [ "$${os}" = "windows" ]; then \ + (cd build/release && zip -q -r $${name}.zip $${name}) || exit 1; \ + else \ + tar -czf build/release/$${name}.tar.gz -C build/release $${name} || exit 1; \ + fi; \ + rm -rf build/release/$${name}; \ + done + $(call cecho,Generating checksums...,$(BOLD_YELLOW)) + @cd build/release && sha256sum *.tar.gz *.zip > checksums.txt + $(call cecho,krbctl release artifacts written to build/release.,$(BOLD_GREEN)) + install/deps: go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@v2.6.0 diff --git a/cmd/admin-connector/main.go b/cmd/admin-connector/main.go index e891ef1..90ce086 100644 --- a/cmd/admin-connector/main.go +++ b/cmd/admin-connector/main.go @@ -66,7 +66,7 @@ func main() { WithName("admin-connector"), ) - zerologr.Info("Starting admin connector", "port", port.Value()) + zerologr.Info("Starting admin connector", "port", port.Value(), "target", target.Value()) signalCtx, signalCancel := signal.NotifyContext( context.Background(), diff --git a/cmd/krbctl/cmd/assets/grafana/kerberos_http.json b/cmd/krbctl/cmd/assets/grafana/kerberos_http.json new file mode 100644 index 0000000..aad2652 --- /dev/null +++ b/cmd/krbctl/cmd/assets/grafana/kerberos_http.json @@ -0,0 +1,2109 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 3, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 27, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "rate(request_count_total[$__rate_interval])", + "fullMetaSearch": false, + "includeNullMetadata": false, + "legendFormat": "{{krb_backend}}: {{http_method}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Rate of requests", + "type": "gauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 9 + }, + "id": 5, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "request_count_total", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: {{http_method}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Request count", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 9 + }, + "id": 19, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "response_total", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: {{http_method}} {{http_status_code}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Response total", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 22 + }, + "id": 20, + "panels": [], + "title": "Responses", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 0, + "y": 23 + }, + "id": 21, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "response_size_bytes_bucket{http_method=\"GET\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: le {{le}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Response size (bytes) bucket: GET", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 8, + "y": 23 + }, + "id": 22, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "response_size_bytes_bucket{http_method=\"POST\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: le {{le}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Response size (bytes) bucket: POST", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 16, + "y": 23 + }, + "id": 23, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "response_size_bytes_bucket{http_method=\"PUT\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: le {{le}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Response size (bytes) bucket: PUT", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 0, + "y": 34 + }, + "id": 24, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "response_size_bytes_bucket{http_method=\"PATCH\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: le {{le}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Response size (bytes) bucket: PATCH", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 8, + "y": 34 + }, + "id": 25, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "response_size_bytes_bucket{http_method=\"DELETE\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: le {{le}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Response size (bytes) bucket: DELETE", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 16, + "y": 34 + }, + "id": 26, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "response_size_bytes_bucket{http_method=\"OPTIONS\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: le {{le}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Response size (bytes) bucket: OPTIONS", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 45 + }, + "id": 4, + "panels": [], + "title": "Requests", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 0, + "y": 46 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "request_duration_milliseconds_bucket{http_method=\"GET\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: le {{le}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Request duration (ms) bucket: GET", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 8, + "y": 46 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "request_duration_milliseconds_bucket{http_method=\"POST\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: le {{le}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Request duration (ms) bucket: POST", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 16, + "y": 46 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "request_duration_milliseconds_bucket{http_method=\"PUT\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: le {{le}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Request duration (ms) bucket: PUT", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 0, + "y": 57 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "request_duration_milliseconds_bucket{http_method=\"PATCH\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: le {{le}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Request duration (ms) bucket: PATCH", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 8, + "y": 57 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "request_duration_milliseconds_bucket{http_method=\"DELETE\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: le {{le}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Request duration (ms) bucket: DELETE", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 16, + "y": 57 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "request_duration_milliseconds_bucket{http_method=\"OPTIONS\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: le {{le}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Request duration (ms) bucket: OPTIONS", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 0, + "y": 68 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "request_size_bytes_bucket{http_method=\"GET\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: le {{le}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Request size (bytes) bucket: GET", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 8, + "y": 68 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "request_size_bytes_bucket{http_method=\"POST\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: le {{le}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Request size (bytes) bucket: POST", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 16, + "y": 68 + }, + "id": 17, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "request_size_bytes_bucket{http_method=\"PUT\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: le {{le}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Request size (bytes) bucket: PUT", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 0, + "y": 79 + }, + "id": 15, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "request_size_bytes_bucket{http_method=\"PATCH\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: le {{le}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Request size (bytes) bucket: PATCH", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 8, + "y": 79 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "request_size_bytes_bucket{http_method=\"DELETE\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: le {{le}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Request size (bytes) bucket: DELETE", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 16, + "y": 79 + }, + "id": 14, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true, + "sortBy": "Name", + "sortDesc": false + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "request_size_bytes_bucket{http_method=\"OPTIONS\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{krb_backend}}: le {{le}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Request size (bytes) bucket: OPTIONS", + "type": "timeseries" + } + ], + "preload": false, + "schemaVersion": 41, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Kerberos HTTP", + "uid": "9179fb85-6e9e-42e5-8527-230ec6d6c0b2", + "version": 1 +} \ No newline at end of file diff --git a/cmd/krbctl/cmd/assets/grafana/kerberos_runtime.json b/cmd/krbctl/cmd/assets/grafana/kerberos_runtime.json new file mode 100644 index 0000000..d1c8311 --- /dev/null +++ b/cmd/krbctl/cmd/assets/grafana/kerberos_runtime.json @@ -0,0 +1,730 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 2, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Goroutines", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 50, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "go_goroutine_count", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{job}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Goroutines", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 21, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "go_processor_limit", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{job}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Processor limit", + "type": "gauge" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 17, + "panels": [], + "title": "Memory", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "go_memory_allocated_bytes_total", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{job}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Heap: allocated bytes", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "exemplar": false, + "expr": "go_memory_allocations_total", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{job}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Heap: allocation total", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 19 + }, + "id": 15, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "go_memory_used_bytes", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "Used {{job}}: {{go_memory_type}}", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "go_memory_limit_bytes", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "Limit {{job}}", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "Memory", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Bytes", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 19 + }, + "id": 14, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "go_memory_gc_goal_bytes", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{job}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "GC goal", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 19, + "panels": [], + "title": "Observability", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 28 + }, + "id": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "disableTextWrap": false, + "editorMode": "builder", + "expr": "promhttp_metric_handler_errors_total", + "fullMetaSearch": false, + "includeNullMetadata": true, + "legendFormat": "{{job}}: cause = {{cause}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "promhttp gathering errors", + "type": "timeseries" + } + ], + "preload": false, + "refresh": "auto", + "schemaVersion": 41, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Kerberos runtime", + "uid": "ec321aef-6a36-42aa-a972-08d3d17660be", + "version": 1 +} \ No newline at end of file diff --git a/cmd/krbctl/cmd/assets/grafana/prometheus.json b/cmd/krbctl/cmd/assets/grafana/prometheus.json new file mode 100644 index 0000000..3b8d794 --- /dev/null +++ b/cmd/krbctl/cmd/assets/grafana/prometheus.json @@ -0,0 +1,573 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 1, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "left", + "cellOptions": { + "type": "auto", + "wrapText": false + }, + "inspect": false + }, + "fieldMinMax": false, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 5, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "frameIndex": 0, + "showHeader": true + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "disableTextWrap": false, + "editorMode": "code", + "exemplar": false, + "expr": "target_info", + "format": "table", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": true, + "legendFormat": "__auto", + "range": false, + "refId": "A", + "useBackend": false + } + ], + "title": "Target information", + "transformations": [ + { + "id": "labelsToFields", + "options": { + "keepLabels": [ + "instance", + "job", + "service.name", + "telemetry.sdk.language", + "telemetry.sdk.name", + "telemetry.sdk.version" + ], + "mode": "columns" + } + }, + { + "id": "filterFieldsByName", + "options": { + "include": { + "names": [ + "instance", + "job", + "service.name", + "Value", + "service.version" + ] + } + } + }, + { + "id": "organize", + "options": { + "excludeByName": {}, + "includeByName": {}, + "indexByName": { + "Value": 4, + "instance": 3, + "job": 2, + "service.name": 0, + "service.version": 1 + }, + "renameByName": {} + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 50, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 5 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "scrape_series_added", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{job}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Scrape series added", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisGridShow": true, + "axisLabel": "Seconds", + "axisPlacement": "left", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 50, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 5 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "scrape_duration_seconds", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{job}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Scrape duration", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 50, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 13 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "scrape_samples_scraped", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{job}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Samples scraped", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": true, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "Count", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 50, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 13 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "scrape_samples_post_metric_relabeling", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{job}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Scrape samples post metric relableing", + "type": "timeseries" + } + ], + "preload": false, + "schemaVersion": 41, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Prometheus status", + "uid": "6d3ea7ab-5878-46f3-9b5f-2a021b205cc5", + "version": 1 +} \ No newline at end of file diff --git a/cmd/krbctl/cmd/assets/jaeger/config-ui.json b/cmd/krbctl/cmd/assets/jaeger/config-ui.json new file mode 100644 index 0000000..9b8681b --- /dev/null +++ b/cmd/krbctl/cmd/assets/jaeger/config-ui.json @@ -0,0 +1,3 @@ +{ + "archiveEnabled": true +} \ No newline at end of file diff --git a/cmd/krbctl/cmd/compose.go b/cmd/krbctl/cmd/compose.go new file mode 100644 index 0000000..78387ef --- /dev/null +++ b/cmd/krbctl/cmd/compose.go @@ -0,0 +1,356 @@ +package cmd + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/charmbracelet/huh" + "github.com/charmbracelet/lipgloss" + "github.com/spf13/cobra" +) + +// composeOptions holds the answers collected from the interactive compose session. +type composeOptions struct { + outputPath string + + // Enablement flags. + includeEcho bool + includeObsStack bool + includePostgres bool + includeConnector bool +} + +func newComposeCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "compose", + Short: "Interactively generate a base compose.yaml for a Kerberos deployment", + Long: `Walks you through a series of prompts to build a compose.yaml that can +be used to run a Kerberos deployment. Optional sections (observability stack, +postgres, admin-connector, echo) can be included or skipped at each step.`, + RunE: runCompose, + } + + cmd.Flags().StringP("output", "o", ".", "Output path where compose.yaml will be written.") + + return cmd +} + +func runCompose(cmd *cobra.Command, _ []string) error { + output, err := cmd.Flags().GetString("output") + if err != nil { + return err + } + + opts := &composeOptions{outputPath: output} + + form := huh.NewForm( + huh.NewGroup( + huh.NewConfirm(). + Title("Include the echo service?"). + Description("Useful for testing backends."). + WithButtonAlignment(lipgloss.Left). + Value(&opts.includeEcho), + + huh.NewConfirm(). + Title("Include the observability stack?"). + Description("Adds Prometheus, Grafana, and Jaeger services."). + WithButtonAlignment(lipgloss.Left). + Value(&opts.includeObsStack), + + huh.NewConfirm(). + Title("Include PostgreSQL as the persistence backend?"). + Description("Uses SQLite by default if skipped."). + WithButtonAlignment(lipgloss.Left). + Value(&opts.includePostgres), + + huh.NewConfirm(). + Title("Include the admin-connector service?"). + WithButtonAlignment(lipgloss.Left). + Value(&opts.includeConnector), + ), + ) + + if err := form.Run(); err != nil { + return fmt.Errorf("prompt cancelled: %w", err) + } + + content := buildCompose(opts) + + //nolint:gosec // welp + if err := os.WriteFile( + filepath.Join(opts.outputPath, "compose.yaml"), []byte(content), 0o644, + ); err != nil { + return fmt.Errorf("failed to write compose file: %w", err) + } + + fmt.Fprintf(os.Stdout, "\ncompose.yaml written to %s\n", opts.outputPath) + + return nil +} + +func buildCompose(opts *composeOptions) string { + var b strings.Builder + + b.WriteString("services:\n") + writePostgresService(&b, opts) + writeSQLiteInitService(&b, opts) + writeKerberosService(&b, opts) + writeEchoService(&b, opts) + writeConnectorService(&b, opts) + writeObsServices(&b, opts) + writeVolumes(&b, opts) + + return b.String() +} + +func writePostgresService(b *strings.Builder, opts *composeOptions) { + if !opts.includePostgres { + return + } + + b.WriteString(` postgres: + image: "postgres:18.4-alpine3.23" + pull_policy: if_not_present + environment: + - POSTGRES_DB=kerberos + - POSTGRES_USER=kerberos + - POSTGRES_PASSWORD=kerberos + restart: on-failure + healthcheck: + test: ["CMD-SHELL", "psql -U kerberos -d kerberos -c 'SELECT 1' -q -t 2>/dev/null | grep -q 1"] + interval: 1s + timeout: 2s + retries: 10 + volumes: + - postgres:/var/lib/postgresql/18/docker + +`) +} + +func writeKerberosService(b *strings.Builder, opts *composeOptions) { + b.WriteString(` kerberos: + image: "ghcr.io/trebent/kerberos:latest" + command: --config /krb.json + pull_policy: if_not_present +`) + + if opts.includePostgres { + b.WriteString(` depends_on: + postgres: + condition: service_healthy +`) + } else { + b.WriteString(` depends_on: + sqlite-init: + condition: service_completed_successfully +`) + } + + b.WriteString(` restart: on-failure + ports: + - 30000:30000 + - 30001:30001 + environment: + - LOG_TO_CONSOLE=1 + - LOG_VERBOSITY=0 + - PORT=30000 + - ADMIN_PORT=30001 +`) + + writeOtelEnv(b, opts.includeObsStack, "kerberos") + + b.WriteString(` volumes: + - ./krb.json:/krb.json:ro +`) + + fmt.Fprintf(b, " %s\n", krbDataMount(opts.includePostgres)) + b.WriteString("\n") +} + +func writeEchoService(b *strings.Builder, opts *composeOptions) { + if !opts.includeEcho { + return + } + + b.WriteString(` echo: + image: "ghcr.io/trebent/kerberos/echo:latest" + pull_policy: if_not_present + restart: on-failure + environment: + - PORT=15000 +`) + + writeOtelEnv(b, opts.includeObsStack, "echo") + b.WriteString("\n") +} + +func writeConnectorService(b *strings.Builder, opts *composeOptions) { + if !opts.includeConnector { + return + } + + b.WriteString(` connector: + image: "ghcr.io/trebent/kerberos/admin-connector:latest" + command: --config /connector.json + pull_policy: if_not_present + depends_on: + kerberos: + condition: service_started +`) + if !opts.includePostgres { + b.WriteString(` sqlite-init: + condition: service_completed_successfully +`) + } + b.WriteString(` ports: + - 30100:30100 +`) + b.WriteString(` restart: on-failure + environment: + - LOG_TO_CONSOLE=true + - LOG_VERBOSITY=0 + - PORT=30100 +`) + + if opts.includeObsStack { + fmt.Fprintf(b, " - TARGET=jaeger:16686\n") + } + + writeOtelEnv(b, opts.includeObsStack, "connector") + + b.WriteString(` volumes: + - ./connector.json:/connector.json:ro +`) + + fmt.Fprintf(b, " %s\n", krbDataMount(opts.includePostgres)) + b.WriteString("\n") +} + +func writeObsServices(b *strings.Builder, opts *composeOptions) { + if !opts.includeObsStack { + return + } + + b.WriteString(` prometheus: + image: "prom/prometheus:v3" + pull_policy: if_not_present + command: ["--config.file=/prometheus.yml", "--storage.tsdb.path", "/prometheus/data", + "--storage.tsdb.retention.size", "1GB"] + restart: on-failure + volumes: + - ./prometheus.yml:/prometheus.yml + - prometheus:/prometheus + + grafana: + image: "grafana/grafana:13.1" + pull_policy: if_not_present + restart: on-failure +`) + if !opts.includePostgres { + b.WriteString(` depends_on: + sqlite-init: + condition: service_completed_successfully +`) + } + b.WriteString(` ports: + - 3000:3000 + volumes: + - ./grafana/grafana.ini:/etc/grafana/grafana.ini + - ./grafana/grafana-datasources.yml:/etc/grafana/provisioning/datasources/grafana-datasources.yml + - ./grafana/grafana-dashboards.yml:/etc/grafana/provisioning/dashboards/grafana-dashboards.yml + - ./grafana/prometheus.json:/var/lib/grafana/prometheus.json + - ./grafana/kerberos_runtime.json:/var/lib/grafana/kerberos_runtime.json + - ./grafana/kerberos_http.json:/var/lib/grafana/kerberos_http.json + - grafana:/var/lib/grafana +`) + fmt.Fprintf(b, " %s\n\n", krbDataMount(opts.includePostgres)) + b.WriteString(` jaeger-init: + image: busybox:1.38 + pull_policy: if_not_present + command: ["sh", "-c", "chown 10001:0 /jaeger"] + restart: on-failure + volumes: + - jaeger:/jaeger + + jaeger: + image: "jaegertracing/jaeger:2.20.0" + pull_policy: if_not_present + depends_on: + jaeger-init: + condition: service_completed_successfully + restart: on-failure + command: --config /jaeger.yml +`) + if !opts.includeConnector { + b.WriteString(` ports: + - 16686:16686 +`) + } + b.WriteString(` volumes: + - ./jaeger.yml:/jaeger.yml + - ./jaeger-config-ui.json:/jaeger-config-ui.json + - jaeger:/jaeger + +`) +} + +func writeSQLiteInitService(b *strings.Builder, opts *composeOptions) { + if opts.includePostgres { + return + } + + b.WriteString(` sqlite-init: + image: busybox:1.38 + pull_policy: if_not_present + command: ["sh", "-c", "chmod 0777 /krbdata && touch /krbdata/krb.db && chmod 0666 /krbdata/krb.db"] + restart: on-failure + volumes: + - krbdata:/krbdata + +`) +} + +func krbDataMount(includePostgres bool) string { + if includePostgres { + return "" + } + + return "- krbdata:/krbdata" +} + +func writeOtelEnv(b *strings.Builder, withObs bool, hostname string) { + if withObs { + fmt.Fprintf(b, " - OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4317\n") + fmt.Fprintf(b, " - OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=grpc\n") + fmt.Fprintf(b, " - OTEL_METRICS_EXPORTER=prometheus\n") + fmt.Fprintf(b, " - OTEL_EXPORTER_PROMETHEUS_HOST=%s\n", hostname) + fmt.Fprintf(b, " - OTEL_EXPORTER_PROMETHEUS_PORT=9464\n") + } else { + b.WriteString(" - OTEL_METRICS_EXPORTER=none\n") + b.WriteString(" - OTEL_TRACES_EXPORTER=none\n") + } +} + +func writeVolumes(b *strings.Builder, opts *composeOptions) { + var volumes []string + + if opts.includePostgres { + volumes = append(volumes, " postgres:") + } else { + volumes = append(volumes, " krbdata:") + } + + if opts.includeObsStack { + volumes = append(volumes, " prometheus:", " grafana:", " jaeger:") + } + + if len(volumes) == 0 { + return + } + + b.WriteString("volumes:\n") + b.WriteString(strings.Join(volumes, "\n")) + b.WriteString("\n") +} diff --git a/cmd/krbctl/cmd/config.go b/cmd/krbctl/cmd/config.go new file mode 100644 index 0000000..0e4005b --- /dev/null +++ b/cmd/krbctl/cmd/config.go @@ -0,0 +1,533 @@ +package cmd + +import ( + "encoding/json" + "errors" + "fmt" + "os" + "path/filepath" + "strconv" + "strings" + + "github.com/charmbracelet/huh" + "github.com/charmbracelet/lipgloss" + "github.com/spf13/cobra" +) + +const ( + driverPostgres = "postgres" + driverSQLite = "sqlite" + defaultKRBDB = "kerberos" + echoBackendName = "echo" + echoBackendHost = "echo" + echoBackendPort = 15000 + jaegerName = "jaeger" + + // scrapeMetricsPort is the default Prometheus exporter port every service + // exposes its metrics on. + scrapeMetricsPort = 9464 + // sqliteSharedPath is the SQLite file location on the shared krbdata volume, + // letting Kerberos and the admin-connector share one database file. + sqliteSharedPath = "/krbdata/krb.db" +) + +// configOptions holds all answers collected from the interactive config session. +type configOptions struct { + outputPath string + + // Kerberos gateway + backends []backendEntry + + // persistence driver selection + driver string // "sqlite" or "postgres" + + // Observability stack (Prometheus/Grafana/Jaeger) config generation + includeObsStack bool + obsOpts obsConfigOptions + + // Admin-connector + includeConnector bool + connectorOpts connectorOptions +} + +type backendEntry struct { + name string + host string + port int + auth bool +} + +// obsConfigOptions holds the answers for the observability stack config section. +type obsConfigOptions struct { + scrapeTargets []string // e.g. ["kerberos","echo","connector","jaeger"] + grafanaAnonymous bool +} + +// connectorOptions holds the answers for the admin-connector config section. +type connectorOptions struct { + allowAllOrigins bool +} + +func newConfigCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "config", + Short: "Interactively generate a base Kerberos configuration file", + Long: `Walks you through a series of prompts to build a base Kerberos JSON +configuration file. Mandatory sections are always included (Kerberos +observability is always enabled); optional sections (per-backend auth, +observability-stack config, postgres persistence, admin-connector) can be +skipped.`, + RunE: runConfig, + } + + cmd.Flags().StringP("output", "o", ".", "Output path where config files will be written.") + + return cmd +} + +func runConfig(cmd *cobra.Command, _ []string) error { + output, err := cmd.Flags().GetString("output") + if err != nil { + return err + } + + opts := &configOptions{ + outputPath: output, + connectorOpts: connectorOptions{ + allowAllOrigins: true, + }, + driver: driverSQLite, + obsOpts: obsConfigOptions{ + grafanaAnonymous: true, + }, + } + + if err := promptBackends(opts); err != nil { + return err + } + + if err := promptFixedSections(opts); err != nil { + return err + } + + // Write krb.json + content, err := buildConfig(opts) + if err != nil { + return fmt.Errorf("failed to build config: %w", err) + } + + //nolint:gosec // welp + if err := os.WriteFile( + filepath.Join(opts.outputPath, "krb.json"), content, 0o644, + ); err != nil { + return fmt.Errorf("failed to write config file: %w", err) + } + + fmt.Fprintf(os.Stdout, "krb.json written to %s\n", opts.outputPath) + + // Write observability stack config files + if opts.includeObsStack { + if err := writeObsFiles(opts.driver, opts); err != nil { + return err + } + } + + // Write connector.json + if opts.includeConnector { + connContent, err := buildConnectorJSON(opts.driver, &opts.connectorOpts) + if err != nil { + return fmt.Errorf("failed to build connector config: %w", err) + } + + //nolint:gosec // welp + if err := os.WriteFile( + filepath.Join(opts.outputPath, "connector.json"), connContent, 0o644, + ); err != nil { + return fmt.Errorf("failed to write connector.json: %w", err) + } + + fmt.Fprintln(os.Stdout, "connector.json written to connector.json") + } + + return nil +} + +// promptBackends collects one or more backend target entries using huh. The echo +// service can be registered as a router backend up front; when present the user +// may finish without registering any manual backend. +func promptBackends(opts *configOptions) error { + if err := promptEchoBackend(opts); err != nil { + return err + } + + for { + name, err := promptBackendName(opts) + if err != nil { + return err + } + + if name == "" { + break + } + + if err := promptBackendDetails(opts, name); err != nil { + return err + } + + addAnother, err := promptAddAnother() + if err != nil { + return err + } + + if !addAnother { + break + } + } + + return nil +} + +// promptEchoBackend asks whether to register the echo service as a backend. +func promptEchoBackend(opts *configOptions) error { + var useEcho bool + + echoForm := huh.NewForm( + huh.NewGroup( + huh.NewConfirm(). + Title("Use the echo service as a backend?"). + Description(fmt.Sprintf( + "Registers echo (%s:%d) as a router backend.", + echoBackendHost, echoBackendPort, + )). + WithButtonAlignment(lipgloss.Left). + Value(&useEcho), + ), + ) + + if err := echoForm.Run(); err != nil { + return fmt.Errorf("prompt cancelled: %w", err) + } + + if useEcho { + opts.backends = append(opts.backends, backendEntry{ + name: echoBackendName, + host: echoBackendHost, + port: echoBackendPort, + }) + } + + return nil +} + +// promptBackendName asks for a backend name. An empty result signals the user is +// done. At least one backend is required, enforced via inline validation. +func promptBackendName(opts *configOptions) (string, error) { + var name string + + form := huh.NewForm( + huh.NewGroup( + huh.NewInput(). + Title(fmt.Sprintf("Backend %d — name", len(opts.backends)+1)). + Description(`Press Enter with an empty name to finish (at least one required).`). + Placeholder("my-api"). + Validate(func(s string) error { + if strings.TrimSpace(s) == "" && len(opts.backends) == 0 { + return errors.New("at least one backend is required") + } + + return nil + }). + Value(&name), + ), + ) + + if err := form.Run(); err != nil { + return "", fmt.Errorf("prompt cancelled: %w", err) + } + + return strings.TrimSpace(name), nil +} + +// promptBackendDetails asks for the host and port of the named backend and +// appends it to the backend list. +func promptBackendDetails(opts *configOptions, name string) error { + var ( + host string + portStr string + ) + + detailForm := huh.NewForm( + huh.NewGroup( + huh.NewInput(). + Title(fmt.Sprintf("Backend %q — host", name)). + Placeholder("localhost"). + Value(&host), + + huh.NewInput(). + Title(fmt.Sprintf("Backend %q — port", name)). + Placeholder("8080"). + Value(&portStr), + ), + ) + + if err := detailForm.Run(); err != nil { + return fmt.Errorf("prompt cancelled: %w", err) + } + + if strings.TrimSpace(host) == "" { + host = "localhost" + } + + opts.backends = append(opts.backends, backendEntry{ + name: name, + host: host, + port: parsePort(portStr), + }) + + return nil +} + +// promptAddAnother asks whether to register another backend. +func promptAddAnother() (bool, error) { + var addAnother bool + + confirmForm := huh.NewForm( + huh.NewGroup( + huh.NewConfirm(). + Title("Add another backend?"). + WithButtonAlignment(lipgloss.Left). + Value(&addAnother), + ), + ) + + if err := confirmForm.Run(); err != nil { + return false, fmt.Errorf("prompt cancelled: %w", err) + } + + return addAnother, nil +} + +// promptFixedSections runs the remaining configuration prompts as a single +// multi-group form so the user can move back and forth between sections with +// shift+tab. Conditional groups are hidden until their toggle is enabled. +func promptFixedSections(opts *configOptions) error { + opts.obsOpts.scrapeTargets = defaultScrapeTargets(opts) + + form := huh.NewForm( + buildPersistenceGroup(opts), + buildAuthGroup(opts), + buildObsToggleGroup(opts), + buildObsOptionsGroup(opts), + buildConnectorToggleGroup(opts), + buildConnectorConfigGroup(opts), + ) + + if err := form.Run(); err != nil { + return fmt.Errorf("prompt cancelled: %w", err) + } + + return nil +} + +// defaultScrapeTargets returns the scrape targets pre-selected by default: +// kerberos, jaeger, and every registered router backend. +func defaultScrapeTargets(opts *configOptions) []string { + targets := []string{defaultKRBDB, jaegerName} + for _, b := range opts.backends { + targets = append(targets, b.name) + } + + return targets +} + +// buildAuthGroup builds a dedicated authentication section with a per-backend +// toggle enabling basic auth for that backend. +func buildAuthGroup(opts *configOptions) *huh.Group { + fields := make([]huh.Field, 0, len(opts.backends)) + for i := range opts.backends { + fields = append(fields, huh.NewConfirm(). + Title(fmt.Sprintf("Enable basic auth for backend %q?", opts.backends[i].name)). + WithButtonAlignment(lipgloss.Left). + Value(&opts.backends[i].auth)) + } + + return huh.NewGroup(fields...).Title("Authentication") +} + +// buildObsToggleGroup builds the dedicated toggle controlling generation of the +// observability stack (Prometheus/Grafana/Jaeger) config files. +func buildObsToggleGroup(opts *configOptions) *huh.Group { + return huh.NewGroup( + huh.NewConfirm(). + Title("Generate observability stack config?"). + Description("Writes Prometheus, Grafana, and Jaeger config files for the " + + "observability stack. (Kerberos observability itself is always enabled.)"). + WithButtonAlignment(lipgloss.Left). + Value(&opts.includeObsStack), + ).Title("Observability stack") +} + +// buildObsOptionsGroup builds the observability stack detail options, hidden +// unless the observability stack toggle is enabled. +func buildObsOptionsGroup(opts *configOptions) *huh.Group { + scrapeOpts := []huh.Option[string]{ + huh.NewOption(fmt.Sprintf("kerberos (port %d)", scrapeMetricsPort), defaultKRBDB), + huh.NewOption("jaeger (port 8888)", jaegerName), + } + for _, b := range opts.backends { + scrapeOpts = append(scrapeOpts, huh.NewOption( + fmt.Sprintf("%s (%s:%d)", b.name, b.host, scrapeMetricsPort), b.name)) + } + + return huh.NewGroup( + huh.NewMultiSelect[string](). + Title("Prometheus scrape targets"). + Description("Select services that should expose metrics to Prometheus. "+ + "The admin-connector is scraped automatically when included."). + Options(scrapeOpts...). + Value(&opts.obsOpts.scrapeTargets), + + huh.NewConfirm(). + Title("Enable Grafana anonymous access?"). + Description("Allows viewing dashboards without logging in."). + WithButtonAlignment(lipgloss.Left). + Value(&opts.obsOpts.grafanaAnonymous), + ).Title("Observability stack options"). + WithHideFunc(func() bool { return !opts.includeObsStack }) +} + +// buildPersistenceGroup builds the Kerberos persistence selection section. +func buildPersistenceGroup(opts *configOptions) *huh.Group { + persistenceOpts := []huh.Option[string]{ + huh.NewOption("SQLite (default, file-based)", driverSQLite), + huh.NewOption("PostgreSQL", driverPostgres), + } + + return huh.NewGroup( + huh.NewSelect[string](). + Title("Persistence backend"). + Options(persistenceOpts...). + Value(&opts.driver), + ).Title("Persistence") +} + +// buildConnectorToggleGroup builds the dedicated admin-connector on/off section. +func buildConnectorToggleGroup(opts *configOptions) *huh.Group { + return huh.NewGroup( + huh.NewConfirm(). + Title("Include the admin-connector?"). + Description("Generates connector.json for the admin-connector service."). + WithButtonAlignment(lipgloss.Left). + Value(&opts.includeConnector), + ).Title("Admin-connector") +} + +// buildConnectorConfigGroup builds the admin-connector config detail section, +// hidden unless the admin-connector toggle is enabled. +func buildConnectorConfigGroup(opts *configOptions) *huh.Group { + return huh.NewGroup( + huh.NewConfirm(). + Title("Allow all CORS origins?"). + Description("Yes allows any origin; No denies all cross-origin requests."). + WithButtonAlignment(lipgloss.Left). + Value(&opts.connectorOpts.allowAllOrigins), + ).Title("Admin-connector config"). + WithHideFunc(func() bool { return !opts.includeConnector }) +} + +func parsePort(raw string) int { + const defaultPort = 8080 + + port, err := strconv.Atoi(strings.TrimSpace(raw)) + if err != nil || port < 1 || port > 65535 { + return defaultPort + } + + return port +} + +//nolint:cyclop // config builder requires branching per optional section +func buildConfig(opts *configOptions) ([]byte, error) { + backends := make([]map[string]any, 0, len(opts.backends)) + for _, b := range opts.backends { + backends = append(backends, map[string]any{ + "name": b.name, + "host": b.host, + "port": b.port, + }) + } + + root := map[string]any{ + "gateway": map[string]any{ + "router": map[string]any{ + "backends": backends, + }, + }, + } + + root["observability"] = map[string]any{ + "enabled": true, + "runtimeMetrics": true, + } + + if authBackends := authEnabledBackends(opts.backends); len(authBackends) > 0 { + root["auth"] = buildAuthSection(authBackends) + } + + root["persistence"] = buildPersistenceSection(opts.driver) + + return json.MarshalIndent(root, "", " ") +} + +// authEnabledBackends returns the subset of backends that have auth enabled. +func authEnabledBackends(backends []backendEntry) []backendEntry { + enabled := make([]backendEntry, 0, len(backends)) + for _, b := range backends { + if b.auth { + enabled = append(enabled, b) + } + } + + return enabled +} + +func buildAuthSection(backends []backendEntry) map[string]any { + mappings := make([]map[string]any, 0, len(backends)) + for _, b := range backends { + mappings = append(mappings, map[string]any{ + "backend": b.name, + "method": "basic", + "exempt": []string{}, + }) + } + + return map[string]any{ + "methods": map[string]any{ + "basic": map[string]any{}, + }, + "scheme": map[string]any{ + "mappings": mappings, + }, + "order": 1, + } +} + +func buildPersistenceSection(mode string) map[string]any { + if mode == driverPostgres { + return map[string]any{ + "driver": driverPostgres, + "address": "postgres:5432", + "postgres": map[string]any{ + "database": defaultKRBDB, + "username": defaultKRBDB, + "password": defaultKRBDB, + "sslMode": "disable", + }, + } + } + + return map[string]any{ + "driver": driverSQLite, + "address": sqliteSharedPath, + } +} diff --git a/cmd/krbctl/cmd/connectorconfig.go b/cmd/krbctl/cmd/connectorconfig.go new file mode 100644 index 0000000..c1f972e --- /dev/null +++ b/cmd/krbctl/cmd/connectorconfig.go @@ -0,0 +1,28 @@ +package cmd + +import ( + "encoding/json" + "fmt" +) + +// buildConnectorJSON generates a minimal connector.json. +func buildConnectorJSON(driver string, opts *connectorOptions) ([]byte, error) { + origins := map[string]any{} + if opts.allowAllOrigins { + origins["allowAll"] = true + } else { + origins["denyAll"] = true + } + + root := map[string]any{ + "origins": origins, + "persistence": buildPersistenceSection(driver), + } + + content, err := json.MarshalIndent(root, "", " ") + if err != nil { + return nil, fmt.Errorf("failed to marshal connector config: %w", err) + } + + return content, nil +} diff --git a/cmd/krbctl/cmd/obsconfig.go b/cmd/krbctl/cmd/obsconfig.go new file mode 100644 index 0000000..f079050 --- /dev/null +++ b/cmd/krbctl/cmd/obsconfig.go @@ -0,0 +1,279 @@ +package cmd + +import ( + _ "embed" + "fmt" + "os" + "path/filepath" + "strings" +) + +//go:embed assets/grafana/prometheus.json +var grafanaDashboardPrometheus []byte + +//go:embed assets/grafana/kerberos_runtime.json +var grafanaDashboardRuntime []byte + +//go:embed assets/grafana/kerberos_http.json +var grafanaDashboardHTTP []byte + +//go:embed assets/jaeger/config-ui.json +var jaegerConfigUI []byte + +// scrapeJob is a resolved Prometheus scrape target (job name + host:port). +type scrapeJob struct { + name string + target string +} + +// writeObsFiles creates all observability config files in the current directory. +func writeObsFiles(driver string, opts *configOptions) error { + prometheusData := []byte(buildPrometheusYML(resolveScrapeJobs(opts))) + if err := writeObsFile( + filepath.Join(opts.outputPath, "prometheus.yml"), prometheusData, + ); err != nil { + return err + } + + grafanaDir := filepath.Join(opts.outputPath, "grafana") + if err := os.MkdirAll(grafanaDir, 0o750); err != nil { + return fmt.Errorf("failed to create grafana directory: %w", err) + } + + grafanaFiles := []struct { + path string + data []byte + }{ + {filepath.Join(grafanaDir, "grafana.ini"), []byte(buildGrafanaINI(driver, &opts.obsOpts))}, + { + filepath.Join(grafanaDir, "grafana-datasources.yml"), + []byte(buildGrafanaDatasourcesYML()), + }, + { + filepath.Join(grafanaDir, "grafana-dashboards.yml"), + []byte(buildGrafanaDashboardsYML()), + }, + {filepath.Join(grafanaDir, "prometheus.json"), grafanaDashboardPrometheus}, + {filepath.Join(grafanaDir, "kerberos_runtime.json"), grafanaDashboardRuntime}, + {filepath.Join(grafanaDir, "kerberos_http.json"), grafanaDashboardHTTP}, + } + + for _, f := range grafanaFiles { + if err := writeObsFile(f.path, f.data); err != nil { + return err + } + } + + if err := writeObsFile( + filepath.Join(opts.outputPath, "jaeger.yml"), []byte(buildJaegerYML()), + ); err != nil { + return err + } + + if err := writeObsFile( + filepath.Join(opts.outputPath, "jaeger-config-ui.json"), jaegerConfigUI, + ); err != nil { + return err + } + + return nil +} + +// writeObsFile writes data to path and prints a confirmation line. +func writeObsFile(path string, data []byte) error { + //nolint:gosec // welp + if err := os.WriteFile(path, data, 0o644); err != nil { + return fmt.Errorf("failed to write %s: %w", path, err) + } + + fmt.Fprintf(os.Stdout, "%s written\n", path) + + return nil +} + +// resolveScrapeJobs turns the selected scrape targets into concrete host:port +// jobs. kerberos and jaeger resolve to their well-known endpoints, every other +// selected target is treated as a registered router backend scraped on the +// default metrics port. The admin-connector is added automatically when the +// connector is included in the deployment. +func resolveScrapeJobs(opts *configOptions) []scrapeJob { + hosts := make(map[string]string, len(opts.backends)) + for _, b := range opts.backends { + hosts[b.name] = b.host + } + + jobs := make([]scrapeJob, 0, len(opts.obsOpts.scrapeTargets)+1) + + for _, target := range opts.obsOpts.scrapeTargets { + switch target { + case defaultKRBDB: + jobs = append( + jobs, + scrapeJob{defaultKRBDB, fmt.Sprintf("%s:%d", defaultKRBDB, scrapeMetricsPort)}, + ) + case jaegerName: + jobs = append(jobs, scrapeJob{jaegerName, "jaeger:8888"}) + default: + host, ok := hosts[target] + if !ok { + continue + } + + jobs = append(jobs, scrapeJob{target, fmt.Sprintf("%s:%d", host, scrapeMetricsPort)}) + } + } + + if opts.includeConnector { + jobs = append(jobs, scrapeJob{"connector", fmt.Sprintf("connector:%d", scrapeMetricsPort)}) + } + + return jobs +} + +// buildPrometheusYML generates a prometheus.yml with scrape configs for the given jobs. +func buildPrometheusYML(jobs []scrapeJob) string { + var b strings.Builder + + b.WriteString("global:\n scrape_interval: 15s\n\nscrape_configs:\n") + + for _, job := range jobs { + fmt.Fprintf(&b, + " - job_name: %s\n static_configs:\n - targets: [\"%s\"]\n", + job.name, job.target, + ) + } + + return b.String() +} + +// buildGrafanaINI generates a slim grafana.ini with only the sections used in this deployment. +func buildGrafanaINI(driver string, opts *obsConfigOptions) string { + var b strings.Builder + + b.WriteString("[database]\n") + + if driver == driverPostgres { + b.WriteString("type = postgres\n") + b.WriteString("host = postgres:5432\n") + b.WriteString("name = kerberos\n") + b.WriteString("user = kerberos\n") + b.WriteString("password = kerberos\n") + } else { + b.WriteString("type = sqlite3\n") + fmt.Fprintf(&b, "path = %s\n", sqliteSharedPath) + } + + b.WriteString("\n[auth.anonymous]\n") + + if opts.grafanaAnonymous { + b.WriteString("enabled = true\n") + b.WriteString("org_name = Main Org.\n") + b.WriteString("org_role = Viewer\n") + } else { + b.WriteString("enabled = false\n") + } + + return b.String() +} + +// buildGrafanaDatasourcesYML generates the Grafana datasource provisioning file. +func buildGrafanaDatasourcesYML() string { + return `apiVersion: 1 + +datasources: + - name: prometheus + type: prometheus + url: http://prometheus:9090 + uid: prometheus +` +} + +// buildGrafanaDashboardsYML generates the Grafana dashboard provisioning file. +func buildGrafanaDashboardsYML() string { + return `apiVersion: 1 + +providers: + - name: "Prometheus status" + type: file + options: + path: /var/lib/grafana/prometheus.json + - name: "Kerberos runtime" + type: file + options: + path: /var/lib/grafana/kerberos_runtime.json + - name: "Kerberos HTTP" + type: file + options: + path: /var/lib/grafana/kerberos_http.json +` +} + +// buildJaegerYML returns the static Jaeger configuration. +func buildJaegerYML() string { + return `service: + extensions: [jaeger_storage, jaeger_query] + pipelines: + traces: + receivers: [otlp] + processors: [batch] + exporters: [jaeger_storage_exporter] + telemetry: + resource: + service.name: jaeger + metrics: + level: detailed + readers: + - pull: + exporter: + prometheus: + host: 0.0.0.0 + port: 8888 + logs: + level: info + +extensions: + jaeger_query: + storage: + traces: badger_store + traces_archive: badger_archive + ui: + config_file: /jaeger-config-ui.json + http: + endpoint: 0.0.0.0:16686 + grpc: + endpoint: 0.0.0.0:16685 + jaeger_storage: + backends: + badger_store: + badger: + directories: + keys: "/jaeger/" + values: "/jaeger/" + ephemeral: false + ttl: + spans: 48h + metrics_update_interval: 10s + badger_archive: + badger: + directories: + keys: "/jaeger/archive/" + values: "/jaeger/archive/" + ephemeral: false + ttl: + spans: 72h + metrics_update_interval: 10s + +receivers: + otlp: + protocols: + grpc: + endpoint: "0.0.0.0:4317" + +processors: + batch: + +exporters: + jaeger_storage_exporter: + trace_storage: badger_store +` +} diff --git a/cmd/krbctl/cmd/root.go b/cmd/krbctl/cmd/root.go new file mode 100644 index 0000000..3019b7b --- /dev/null +++ b/cmd/krbctl/cmd/root.go @@ -0,0 +1,31 @@ +// Package cmd contains all krbctl CLI commands. +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +// version is the krbctl version. It defaults to "unset" and is overridden at +// build time via -ldflags "-X github.com/trebent/kerberos/cmd/krbctl/cmd.version=...". +var version = "unset" + +// Execute adds all child commands to the root command and runs it. +func Execute() error { + root := &cobra.Command{ + Use: "krbctl", + Version: version, + Short: "krbctl is the Kerberos deployment CLI", + Long: fmt.Sprintf(`krbctl helps you set up a Kerberos deployment by generating +a base compose.yaml and a base kerberos configuration file through +interactive prompts. + +Version: %s`, version), + } + + root.AddCommand(newComposeCmd()) + root.AddCommand(newConfigCmd()) + + return root.Execute() +} diff --git a/cmd/krbctl/main.go b/cmd/krbctl/main.go new file mode 100644 index 0000000..e4fe07b --- /dev/null +++ b/cmd/krbctl/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "os" + + "github.com/trebent/kerberos/cmd/krbctl/cmd" +) + +func main() { + if err := cmd.Execute(); err != nil { + os.Exit(1) + } +} diff --git a/go.mod b/go.mod index 757300f..e69791a 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,17 @@ module github.com/trebent/kerberos -go 1.26.5 +go 1.26.6 require ( + github.com/charmbracelet/huh v1.0.0 + github.com/charmbracelet/lipgloss v1.1.0 github.com/getkin/kin-openapi v0.146.0 github.com/go-logr/logr v1.4.4 github.com/google/uuid v1.6.0 github.com/lib/pq v1.12.3 github.com/oapi-codegen/nethttp-middleware v1.2.0 github.com/oapi-codegen/runtime v1.7.0 + github.com/spf13/cobra v1.9.1 github.com/trebent/envparser v1.0.8 github.com/trebent/zerologr v1.1.1 github.com/xeipuuv/gojsonschema v1.2.0 @@ -26,17 +29,36 @@ require ( require ( github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect + github.com/atotto/clipboard v0.1.4 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/catppuccin/go v0.3.0 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 // indirect + github.com/charmbracelet/bubbletea v1.3.6 // indirect + github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect + github.com/charmbracelet/x/ansi v0.9.3 // indirect + github.com/charmbracelet/x/cellbuf v0.0.13 // indirect + github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect + github.com/charmbracelet/x/term v0.2.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dustin/go-humanize v1.0.1 // indirect + github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v1.0.0 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-colorable v0.1.15 // indirect github.com/mattn/go-isatty v0.0.24 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect + github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/termenv v0.16.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/ncruces/go-strftime v1.0.0 // indirect github.com/oasdiff/yaml v0.1.1 // indirect @@ -48,10 +70,13 @@ require ( github.com/prometheus/otlptranslator v1.0.0 // indirect github.com/prometheus/procfs v0.21.1 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/rs/zerolog v1.35.1 // indirect github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect + github.com/spf13/pflag v1.0.6 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/bridges/prometheus v0.70.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.21.0 // indirect @@ -69,6 +94,7 @@ require ( go.opentelemetry.io/otel/sdk/log v0.21.0 // indirect go.opentelemetry.io/proto/otlp v1.11.0 // indirect golang.org/x/net v0.57.0 // indirect + golang.org/x/sync v0.22.0 // indirect golang.org/x/sys v0.47.0 // indirect golang.org/x/text v0.41.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d // indirect diff --git a/go.sum b/go.sum index 7bb639e..eb012ab 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,54 @@ +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3vj1nolY= +github.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= +github.com/catppuccin/go v0.3.0 h1:d+0/YicIq+hSTo5oPuRi5kOpqkVA5tAsU6dNhvRu+aY= +github.com/catppuccin/go v0.3.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 h1:JFgG/xnwFfbezlUnFMJy0nusZvytYysV4SCS2cYbvws= +github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7/go.mod h1:ISC1gtLcVilLOf23wvTfoQuYbW2q0JevFxPfUzZ9Ybw= +github.com/charmbracelet/bubbletea v1.3.6 h1:VkHIxPJQeDt0aFJIsVxw8BQdh/F/L2KKZGsK6et5taU= +github.com/charmbracelet/bubbletea v1.3.6/go.mod h1:oQD9VCRQFF8KplacJLo28/jofOI2ToOfGYeFgBBxHOc= +github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= +github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= +github.com/charmbracelet/huh v1.0.0 h1:wOnedH8G4qzJbmhftTqrpppyqHakl/zbbNdXIWJyIxw= +github.com/charmbracelet/huh v1.0.0/go.mod h1:5YVc+SlZ1IhQALxRPpkGwwEKftN/+OlJlnJYlDRFqN4= +github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= +github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= +github.com/charmbracelet/x/ansi v0.9.3 h1:BXt5DHS/MKF+LjuK4huWrC6NCvHtexww7dMayh6GXd0= +github.com/charmbracelet/x/ansi v0.9.3/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE= +github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k= +github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= +github.com/charmbracelet/x/conpty v0.1.0 h1:4zc8KaIcbiL4mghEON8D72agYtSeIgq8FSThSPQIb+U= +github.com/charmbracelet/x/conpty v0.1.0/go.mod h1:rMFsDJoDwVmiYM10aD4bH2XiRgwI7NYJtQgl5yskjEQ= +github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86 h1:JSt3B+U9iqk37QUU2Rvb6DSBYRLtWqFqfxf8l5hOZUA= +github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0= +github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ= +github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= +github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 h1:qko3AQ4gK1MTS/de7F5hPGx6/k1u0w4TeYmBFwzYVP4= +github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ= +github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= +github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= +github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY= +github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo= +github.com/charmbracelet/x/xpty v0.1.2 h1:Pqmu4TEJ8KeA9uSkISKMU3f+C1F6OGBn8ABuGlqCbtI= +github.com/charmbracelet/x/xpty v0.1.2/go.mod h1:XK2Z0id5rtLWcpeNiMYBccNNBrP2IJnzHI0Lq13Xzq4= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -15,6 +56,8 @@ github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxK github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= +github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/getkin/kin-openapi v0.146.0 h1:RA/1RdxrSJW4oc1+6IfnYB6AO9CaGy8GTKPh0k4Ordo= github.com/getkin/kin-openapi v0.146.0/go.mod h1:3BH9M9XDe/y9M5DSvEocVYAYq1w0qrhJHjC/vZi0AaY= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -40,6 +83,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF2 github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= github.com/klauspost/compress v1.19.1 h1:VsB4HPswih7mmZ8WleSFQ75c/Ui1M4trX5oAsJnhSlk= github.com/klauspost/compress v1.19.1/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= @@ -51,10 +96,24 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ= github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI= github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= +github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= @@ -84,12 +143,20 @@ github.com/prometheus/procfs v0.21.1 h1:GljZCt+zSTS+NZq88cyQ1LjZ+RCHp3uVuabBWA5+ github.com/prometheus/procfs v0.21.1/go.mod h1:aB55Cww9pdSJVHk0hUf0inxWyyjPogFIjmHKYgMKmtY= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI= github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -106,6 +173,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/bridges/prometheus v0.70.0 h1:qU2CqTGdlstwoVhu1WfjJJ3z2ntcNjTJO0ksTsFKzPI= @@ -162,12 +231,15 @@ go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8= +golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= @@ -186,6 +258,7 @@ google.golang.org/grpc v1.83.0 h1:JeNZEKJFbQxArAMl+hiytHauacDNqJUllNfmIMmpqnQ= google.golang.org/grpc v1.83.0/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/test/suites/go.sum b/test/suites/go.sum index 693d205..bd35a10 100644 --- a/test/suites/go.sum +++ b/test/suites/go.sum @@ -16,8 +16,6 @@ github.com/dprotaso/go-yit v0.0.0-20260623150633-6f1ed93922d1/go.mod h1:EjiB/8UO github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/getkin/kin-openapi v0.145.0 h1:htBX+Q7SevVaCUqymFegUKzH2WCbewl9tsmyn2FMGWY= -github.com/getkin/kin-openapi v0.145.0/go.mod h1:3BH9M9XDe/y9M5DSvEocVYAYq1w0qrhJHjC/vZi0AaY= github.com/getkin/kin-openapi v0.146.0 h1:RA/1RdxrSJW4oc1+6IfnYB6AO9CaGy8GTKPh0k4Ordo= github.com/getkin/kin-openapi v0.146.0/go.mod h1:3BH9M9XDe/y9M5DSvEocVYAYq1w0qrhJHjC/vZi0AaY= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= @@ -82,16 +80,12 @@ github.com/prometheus/common v0.70.1 h1:1HvjP4D5oL3t8RsPlwxA9onvvStjtIHYE5XuuwOi github.com/prometheus/common v0.70.1/go.mod h1:VdFUQDMZK3VLkurFUVhia6uys/0suUp86TJz5qbJRhc= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 h1:1EYB5IzjZawrrnELUi78f9fPu57HuXjmddZPjrls/28= github.com/santhosh-tekuri/jsonschema/v6 v6.0.3/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/speakeasy-api/jsonpath v0.6.3 h1:c+QPwzAOdrWvzycuc9HFsIZcxKIaWcNpC+xhOW9rJxU= github.com/speakeasy-api/jsonpath v0.6.3/go.mod h1:2cXloNuQ+RSXi5HTRaeBh7JEmjRXTiaKpFTdZiL7URI= -github.com/speakeasy-api/openapi v1.24.0 h1:opoD27rupX7zBVPq1HkIGLeMOzNNA7JalhYP8q34i04= -github.com/speakeasy-api/openapi v1.24.0/go.mod h1:g3+dIMe0AYgbbGvnlQZqesmjAVWSm9BmsjLevnefQrg= github.com/speakeasy-api/openapi v1.24.1 h1:e8rkoiq1q8vJ/Ru1pjdlABlgkbG581M4XRadhaHtT3c= github.com/speakeasy-api/openapi v1.24.1/go.mod h1:9gGkzi9jNspEbcB08zta+IjzAi5Zy4QgSEQfF/LSrbQ= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= @@ -107,27 +101,20 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= -go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= -go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= -go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= -go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= -go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= -go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= -go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= -go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= -go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= +go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= +go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= -go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= -go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= go.yaml.in/yaml/v4 v4.0.0-rc.6 h1:1h7H1ohdUh93/FyE4YaDa1Zh64K6VVbjF4K6WUxMtH4= @@ -174,12 +161,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260724162435-b2f20204f0df h1:O3ig1i5WDDzsVzRp+cCdgelT9vXnlnOFdlEeFtL4HCc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260724162435-b2f20204f0df/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/genproto/googleapis/rpc v0.0.0-20260807164820-c8921c73eeea h1:kVhQEPTpKQahD5+JSBTfBB19wcgQTTjAIn45MBqnyHk= google.golang.org/genproto/googleapis/rpc v0.0.0-20260807164820-c8921c73eeea/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= -google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= google.golang.org/grpc v1.83.0 h1:JeNZEKJFbQxArAMl+hiytHauacDNqJUllNfmIMmpqnQ= google.golang.org/grpc v1.83.0/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=