diff --git a/.github/workflows/callable-test-krbctl.yaml b/.github/workflows/callable-test-krbctl.yaml new file mode 100644 index 0000000..26bf96b --- /dev/null +++ b/.github/workflows/callable-test-krbctl.yaml @@ -0,0 +1,64 @@ +name: krbctl tests + +on: + workflow_call: + +permissions: + contents: read + +jobs: + krbctl-test: + 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: test/suites/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 cmd/krbctl -type f -name '*.go' -print0 | sort -z | xargs -0 cat + cat test/suites/go.mod test/suites/go.sum + find test/suites/krbctl -type f -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-test-go-mod-${{ runner.os }}-${{ hashFiles('test/suites/go.sum') }} + + - name: Cache Go build cache + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/.cache/go-build + key: krbctl-test-go-build-${{ runner.os }}-${{ steps.build-cache-key.outputs.checksum }} + restore-keys: | + krbctl-test-go-build-${{ runner.os }}- + + - name: Build krbctl + run: make build/krbctl + + - name: Run krbctl tests + run: make test/krbctl/json + + - name: Publish krbctl test results + uses: dorny/test-reporter@a43b3a5f7366b97d083190328d2c652e1a8b6aa2 # v3.0.0 + if: always() + with: + name: krbctl Tests + path: build/krbctl-test-output.json + reporter: golang-json + fail-on-error: "false" diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index e8476dc..2f15e71 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -40,3 +40,7 @@ jobs: needs: image uses: ./.github/workflows/callable-test-connector.yaml secrets: inherit + + krbctl-test: + uses: ./.github/workflows/callable-test-krbctl.yaml + secrets: inherit diff --git a/Makefile b/Makefile index 660eb49..ca12967 100644 --- a/Makefile +++ b/Makefile @@ -467,6 +467,15 @@ test/connector/json: @mkdir -p build @cd test/suites/connector && go test -v -json ./... -count=1 -failfast > $(CURDIR)/build/connector-test-output.json +test/krbctl: krbctl/build + $(call cecho,Running krbctl tests for Kerberos...,$(BOLD_YELLOW)) + @cd test/suites/krbctl && KRBCTL_BIN=$(CURDIR)/build/krbctl go test -v ./... -count=1 -failfast + +test/krbctl/json: krbctl/build + $(call cecho,Running krbctl tests for Kerberos...,$(BOLD_YELLOW)) + @mkdir -p build + @cd test/suites/krbctl && KRBCTL_BIN=$(CURDIR)/build/krbctl go test -v -json ./... -count=1 -failfast > $(CURDIR)/build/krbctl-test-output.json + test/unit: $(call cecho,Running unit tests for Kerberos...,$(BOLD_YELLOW)) @mkdir -p build diff --git a/cmd/krbctl/cmd/compose.go b/cmd/krbctl/cmd/compose.go index 78387ef..0f1a47d 100644 --- a/cmd/krbctl/cmd/compose.go +++ b/cmd/krbctl/cmd/compose.go @@ -33,6 +33,15 @@ postgres, admin-connector, echo) can be included or skipped at each step.`, } cmd.Flags().StringP("output", "o", ".", "Output path where compose.yaml will be written.") + cmd.Flags().BoolP("non-interactive", "y", false, + "Skip prompts and build compose.yaml from flag values.") + cmd.Flags().Bool("echo", false, "Include the echo service. (non-interactive mode only)") + cmd.Flags().Bool("obs-stack", false, + "Include the observability stack. (non-interactive mode only)") + cmd.Flags().Bool("postgres", false, + "Use PostgreSQL as the persistence backend. (non-interactive mode only)") + cmd.Flags().Bool("connector", false, + "Include the admin-connector service. (non-interactive mode only)") return cmd } @@ -43,8 +52,38 @@ func runCompose(cmd *cobra.Command, _ []string) error { return err } + nonInteractive, err := cmd.Flags().GetBool("non-interactive") + if err != nil { + return err + } + opts := &composeOptions{outputPath: output} + if nonInteractive { + if err := collectComposeFromFlags(cmd, opts); err != nil { + return err + } + } else if err := collectComposeInteractive(opts); err != nil { + return 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 +} + +// collectComposeInteractive drives the interactive huh form, populating opts +// with the user's answers. +func collectComposeInteractive(opts *composeOptions) error { form := huh.NewForm( huh.NewGroup( huh.NewConfirm(). @@ -76,16 +115,29 @@ func runCompose(cmd *cobra.Command, _ []string) error { return fmt.Errorf("prompt cancelled: %w", err) } - content := buildCompose(opts) + return nil +} - //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) +// collectComposeFromFlags populates opts from the command's flag values for +// non-interactive runs. +func collectComposeFromFlags(cmd *cobra.Command, opts *composeOptions) error { + var err error + + if opts.includeEcho, err = cmd.Flags().GetBool("echo"); err != nil { + return err } - fmt.Fprintf(os.Stdout, "\ncompose.yaml written to %s\n", opts.outputPath) + if opts.includeObsStack, err = cmd.Flags().GetBool("obs-stack"); err != nil { + return err + } + + if opts.includePostgres, err = cmd.Flags().GetBool("postgres"); err != nil { + return err + } + + if opts.includeConnector, err = cmd.Flags().GetBool("connector"); err != nil { + return err + } return nil } diff --git a/cmd/krbctl/cmd/config.go b/cmd/krbctl/cmd/config.go index 0e4005b..4919f20 100644 --- a/cmd/krbctl/cmd/config.go +++ b/cmd/krbctl/cmd/config.go @@ -23,6 +23,10 @@ const ( echoBackendPort = 15000 jaegerName = "jaeger" + // defaultBackendHost is the fallback host used when a backend is registered + // without an explicit host. + defaultBackendHost = "localhost" + // scrapeMetricsPort is the default Prometheus exporter port every service // exposes its metrics on. scrapeMetricsPort = 9464 @@ -81,6 +85,25 @@ skipped.`, } cmd.Flags().StringP("output", "o", ".", "Output path where config files will be written.") + cmd.Flags().BoolP("non-interactive", "y", false, + "Skip prompts and build the configuration from flag values.") + cmd.Flags().Bool("echo-backend", false, + "Register the built-in echo service as a router backend. (non-interactive mode only)") + cmd.Flags().StringArray("backend", nil, + "Router backend as 'name=..,host=..,port=..,auth=..' (repeatable). (non-interactive mode only)") + cmd.Flags().String("driver", driverSQLite, + "Persistence driver: sqlite or postgres. (non-interactive mode only)") + cmd.Flags().Bool("obs-stack", false, + "Generate observability stack config files. (non-interactive mode only)") + cmd.Flags().Bool("grafana-anonymous", true, + "Enable Grafana anonymous access. (non-interactive mode only)") + cmd.Flags().StringArray("scrape-target", nil, + "Prometheus scrape target (repeatable); defaults to kerberos, jaeger and all backends. "+ + "(non-interactive mode only)") + cmd.Flags().Bool("connector", false, + "Include the admin-connector (generates connector.json). (non-interactive mode only)") + cmd.Flags().Bool("connector-allow-all-origins", true, + "Allow all CORS origins for the admin-connector. (non-interactive mode only)") return cmd } @@ -91,6 +114,11 @@ func runConfig(cmd *cobra.Command, _ []string) error { return err } + nonInteractive, err := cmd.Flags().GetBool("non-interactive") + if err != nil { + return err + } + opts := &configOptions{ outputPath: output, connectorOpts: connectorOptions{ @@ -102,11 +130,11 @@ func runConfig(cmd *cobra.Command, _ []string) error { }, } - if err := promptBackends(opts); err != nil { - return err - } - - if err := promptFixedSections(opts); err != nil { + if nonInteractive { + if err := collectConfigFromFlags(cmd, opts); err != nil { + return err + } + } else if err := collectConfigInteractive(opts); err != nil { return err } @@ -152,6 +180,148 @@ func runConfig(cmd *cobra.Command, _ []string) error { return nil } +// collectConfigInteractive drives the interactive prompt sequence, populating +// opts with the user's answers. +func collectConfigInteractive(opts *configOptions) error { + if err := promptBackends(opts); err != nil { + return err + } + + if err := promptFixedSections(opts); err != nil { + return err + } + + return nil +} + +// collectConfigFromFlags populates opts from the command's flag values for +// non-interactive runs. +func collectConfigFromFlags(cmd *cobra.Command, opts *configOptions) error { + echoBackend, err := cmd.Flags().GetBool("echo-backend") + if err != nil { + return err + } + + if echoBackend { + opts.backends = append(opts.backends, backendEntry{ + name: echoBackendName, + host: echoBackendHost, + port: echoBackendPort, + }) + } + + backendSpecs, err := cmd.Flags().GetStringArray("backend") + if err != nil { + return err + } + + for _, spec := range backendSpecs { + backend, err := parseBackendFlag(spec) + if err != nil { + return fmt.Errorf("parse backend %q: %w", spec, err) + } + + opts.backends = append(opts.backends, backend) + } + + if len(opts.backends) == 0 { + return errors.New("at least one backend is required (use --echo-backend or --backend)") + } + + if opts.driver, err = cmd.Flags().GetString("driver"); err != nil { + return err + } + + if opts.driver != driverSQLite && opts.driver != driverPostgres { + return fmt.Errorf("invalid driver %q: must be %q or %q", + opts.driver, driverSQLite, driverPostgres) + } + + if opts.includeObsStack, err = cmd.Flags().GetBool("obs-stack"); err != nil { + return err + } + + if opts.obsOpts.grafanaAnonymous, err = cmd.Flags().GetBool("grafana-anonymous"); err != nil { + return err + } + + scrapeTargets, err := cmd.Flags().GetStringArray("scrape-target") + if err != nil { + return err + } + + if len(scrapeTargets) > 0 { + opts.obsOpts.scrapeTargets = scrapeTargets + } else { + opts.obsOpts.scrapeTargets = defaultScrapeTargets(opts) + } + + if opts.includeConnector, err = cmd.Flags().GetBool("connector"); err != nil { + return err + } + + if opts.connectorOpts.allowAllOrigins, err = cmd.Flags().GetBool( + "connector-allow-all-origins"); err != nil { + return err + } + + return nil +} + +// parseBackendFlag parses a single --backend spec of the form +// "name=..,host=..,port=..,auth=..". Only name is mandatory; host defaults to +// localhost, port to the default backend port, and auth to false. +func parseBackendFlag(spec string) (backendEntry, error) { + backend := backendEntry{host: defaultBackendHost} + + for _, part := range strings.Split(spec, ",") { + part = strings.TrimSpace(part) + if part == "" { + continue + } + + key, val, ok := strings.Cut(part, "=") + if !ok { + return backendEntry{}, fmt.Errorf("invalid segment %q: expected key=value", part) + } + + key = strings.TrimSpace(key) + val = strings.TrimSpace(val) + + switch key { + case "name": + backend.name = val + case "host": + backend.host = val + case "port": + backend.port = parsePort(val) + case "auth": + auth, err := strconv.ParseBool(val) + if err != nil { + return backendEntry{}, fmt.Errorf("invalid auth %q: %w", val, err) + } + + backend.auth = auth + default: + return backendEntry{}, fmt.Errorf("unknown key %q", key) + } + } + + if backend.name == "" { + return backendEntry{}, errors.New("backend name is required") + } + + if backend.host == "" { + backend.host = defaultBackendHost + } + + if backend.port == 0 { + backend.port = parsePort("") + } + + return backend, 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. @@ -260,7 +430,7 @@ func promptBackendDetails(opts *configOptions, name string) error { huh.NewGroup( huh.NewInput(). Title(fmt.Sprintf("Backend %q — host", name)). - Placeholder("localhost"). + Placeholder(defaultBackendHost). Value(&host), huh.NewInput(). @@ -275,7 +445,7 @@ func promptBackendDetails(opts *configOptions, name string) error { } if strings.TrimSpace(host) == "" { - host = "localhost" + host = defaultBackendHost } opts.backends = append(opts.backends, backendEntry{ diff --git a/test/suites/krbctl/compose_test.go b/test/suites/krbctl/compose_test.go new file mode 100644 index 0000000..c5dcefd --- /dev/null +++ b/test/suites/krbctl/compose_test.go @@ -0,0 +1,24 @@ +package krbctl + +import ( + "path/filepath" + "testing" +) + +// TestComposeNonInteractive generates a full compose.yaml (echo + observability +// stack + postgres + admin-connector) in non-interactive mode and validates it +// against the golden fixture. +func TestComposeNonInteractive(t *testing.T) { + dir := t.TempDir() + + runKrbctl(t, "compose", "-y", + "--echo", + "--obs-stack", + "--postgres", + "--connector", + "-o", dir) + + assertGoldenFile(t, + filepath.Join(dir, "compose.yaml"), + filepath.Join("testdata", "compose", "compose.yaml")) +} diff --git a/test/suites/krbctl/config_test.go b/test/suites/krbctl/config_test.go new file mode 100644 index 0000000..2e27a0b --- /dev/null +++ b/test/suites/krbctl/config_test.go @@ -0,0 +1,37 @@ +package krbctl + +import ( + "path/filepath" + "testing" +) + +// TestConfigNonInteractive generates a full Kerberos configuration (echo backend +// + one auth-enabled backend + postgres + observability stack + admin-connector) +// in non-interactive mode and validates the dynamically-built config files +// against golden fixtures. Embedded static assets (grafana dashboards, jaeger +// config) are intentionally not compared. +func TestConfigNonInteractive(t *testing.T) { + dir := t.TempDir() + + runKrbctl(t, "config", "-y", + "--echo-backend", + "--backend", "name=api,host=api,port=8080,auth=true", + "--driver", "postgres", + "--obs-stack", + "--connector", + "-o", dir) + + files := []string{ + "krb.json", + "connector.json", + "prometheus.yml", + filepath.Join("grafana", "grafana.ini"), + filepath.Join("grafana", "grafana-datasources.yml"), + } + + for _, f := range files { + assertGoldenFile(t, + filepath.Join(dir, f), + filepath.Join("testdata", "config", f)) + } +} diff --git a/test/suites/krbctl/helpers_test.go b/test/suites/krbctl/helpers_test.go new file mode 100644 index 0000000..0ee985a --- /dev/null +++ b/test/suites/krbctl/helpers_test.go @@ -0,0 +1,40 @@ +package krbctl + +import ( + "bytes" + "os" + "os/exec" + "testing" +) + +// runKrbctl runs the krbctl binary with the given args, failing the test on a +// non-zero exit and surfacing the combined output for diagnostics. +func runKrbctl(t *testing.T, args ...string) { + t.Helper() + + out, err := exec.Command(krbctlBin, args...).CombinedOutput() + if err != nil { + t.Fatalf("krbctl %v failed: %v\n%s", args, err, out) + } +} + +// assertGoldenFile compares the file at genPath byte-for-byte against the golden +// fixture at goldenPath. +func assertGoldenFile(t *testing.T, genPath, goldenPath string) { + t.Helper() + + got, err := os.ReadFile(genPath) + if err != nil { + t.Fatalf("read generated file %s: %v", genPath, err) + } + + want, err := os.ReadFile(goldenPath) + if err != nil { + t.Fatalf("read golden file %s: %v", goldenPath, err) + } + + if !bytes.Equal(got, want) { + t.Errorf("generated %s does not match golden %s\n--- got ---\n%s\n--- want ---\n%s", + genPath, goldenPath, got, want) + } +} diff --git a/test/suites/krbctl/main_test.go b/test/suites/krbctl/main_test.go new file mode 100644 index 0000000..a56a07d --- /dev/null +++ b/test/suites/krbctl/main_test.go @@ -0,0 +1,28 @@ +// Package krbctl contains the black-box integration suite for the krbctl CLI. +// Each test runs the real krbctl binary (located via the KRBCTL_BIN environment +// variable) in non-interactive mode and validates the generated files against +// the golden fixtures under testdata/. +package krbctl + +import ( + "os" + "testing" +) + +// krbctlBin is the path to the krbctl binary under test, taken from KRBCTL_BIN. +var krbctlBin string + +func TestMain(m *testing.M) { + krbctlBin = os.Getenv("KRBCTL_BIN") + if krbctlBin == "" { + println("KRBCTL_BIN is not set; build krbctl and set KRBCTL_BIN to its path") + os.Exit(1) + } + + if _, err := os.Stat(krbctlBin); err != nil { + println("KRBCTL_BIN does not point to an existing binary:", krbctlBin) + os.Exit(1) + } + + os.Exit(m.Run()) +} diff --git a/test/suites/krbctl/testdata/compose/compose.yaml b/test/suites/krbctl/testdata/compose/compose.yaml new file mode 100644 index 0000000..8ea61d4 --- /dev/null +++ b/test/suites/krbctl/testdata/compose/compose.yaml @@ -0,0 +1,130 @@ +services: + 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 + + kerberos: + image: "ghcr.io/trebent/kerberos:latest" + command: --config /krb.json + pull_policy: if_not_present + depends_on: + postgres: + condition: service_healthy + restart: on-failure + ports: + - 30000:30000 + - 30001:30001 + environment: + - LOG_TO_CONSOLE=1 + - LOG_VERBOSITY=0 + - PORT=30000 + - ADMIN_PORT=30001 + - OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4317 + - OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=grpc + - OTEL_METRICS_EXPORTER=prometheus + - OTEL_EXPORTER_PROMETHEUS_HOST=kerberos + - OTEL_EXPORTER_PROMETHEUS_PORT=9464 + volumes: + - ./krb.json:/krb.json:ro + + + echo: + image: "ghcr.io/trebent/kerberos/echo:latest" + pull_policy: if_not_present + restart: on-failure + environment: + - PORT=15000 + - OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4317 + - OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=grpc + - OTEL_METRICS_EXPORTER=prometheus + - OTEL_EXPORTER_PROMETHEUS_HOST=echo + - OTEL_EXPORTER_PROMETHEUS_PORT=9464 + + connector: + image: "ghcr.io/trebent/kerberos/admin-connector:latest" + command: --config /connector.json + pull_policy: if_not_present + depends_on: + kerberos: + condition: service_started + ports: + - 30100:30100 + restart: on-failure + environment: + - LOG_TO_CONSOLE=true + - LOG_VERBOSITY=0 + - PORT=30100 + - TARGET=jaeger:16686 + - OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4317 + - OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=grpc + - OTEL_METRICS_EXPORTER=prometheus + - OTEL_EXPORTER_PROMETHEUS_HOST=connector + - OTEL_EXPORTER_PROMETHEUS_PORT=9464 + volumes: + - ./connector.json:/connector.json:ro + + + 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 + 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 + + + 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 + volumes: + - ./jaeger.yml:/jaeger.yml + - ./jaeger-config-ui.json:/jaeger-config-ui.json + - jaeger:/jaeger + +volumes: + postgres: + prometheus: + grafana: + jaeger: diff --git a/test/suites/krbctl/testdata/config/connector.json b/test/suites/krbctl/testdata/config/connector.json new file mode 100644 index 0000000..75e44af --- /dev/null +++ b/test/suites/krbctl/testdata/config/connector.json @@ -0,0 +1,15 @@ +{ + "origins": { + "allowAll": true + }, + "persistence": { + "address": "postgres:5432", + "driver": "postgres", + "postgres": { + "database": "kerberos", + "password": "kerberos", + "sslMode": "disable", + "username": "kerberos" + } + } +} \ No newline at end of file diff --git a/test/suites/krbctl/testdata/config/grafana/grafana-datasources.yml b/test/suites/krbctl/testdata/config/grafana/grafana-datasources.yml new file mode 100644 index 0000000..e77133b --- /dev/null +++ b/test/suites/krbctl/testdata/config/grafana/grafana-datasources.yml @@ -0,0 +1,7 @@ +apiVersion: 1 + +datasources: + - name: prometheus + type: prometheus + url: http://prometheus:9090 + uid: prometheus diff --git a/test/suites/krbctl/testdata/config/grafana/grafana.ini b/test/suites/krbctl/testdata/config/grafana/grafana.ini new file mode 100644 index 0000000..e44fb85 --- /dev/null +++ b/test/suites/krbctl/testdata/config/grafana/grafana.ini @@ -0,0 +1,11 @@ +[database] +type = postgres +host = postgres:5432 +name = kerberos +user = kerberos +password = kerberos + +[auth.anonymous] +enabled = true +org_name = Main Org. +org_role = Viewer diff --git a/test/suites/krbctl/testdata/config/krb.json b/test/suites/krbctl/testdata/config/krb.json new file mode 100644 index 0000000..9cfa3c5 --- /dev/null +++ b/test/suites/krbctl/testdata/config/krb.json @@ -0,0 +1,47 @@ +{ + "auth": { + "methods": { + "basic": {} + }, + "order": 1, + "scheme": { + "mappings": [ + { + "backend": "api", + "exempt": [], + "method": "basic" + } + ] + } + }, + "gateway": { + "router": { + "backends": [ + { + "host": "echo", + "name": "echo", + "port": 15000 + }, + { + "host": "api", + "name": "api", + "port": 8080 + } + ] + } + }, + "observability": { + "enabled": true, + "runtimeMetrics": true + }, + "persistence": { + "address": "postgres:5432", + "driver": "postgres", + "postgres": { + "database": "kerberos", + "password": "kerberos", + "sslMode": "disable", + "username": "kerberos" + } + } +} \ No newline at end of file diff --git a/test/suites/krbctl/testdata/config/prometheus.yml b/test/suites/krbctl/testdata/config/prometheus.yml new file mode 100644 index 0000000..0fb5ebd --- /dev/null +++ b/test/suites/krbctl/testdata/config/prometheus.yml @@ -0,0 +1,19 @@ +global: + scrape_interval: 15s + +scrape_configs: + - job_name: kerberos + static_configs: + - targets: ["kerberos:9464"] + - job_name: jaeger + static_configs: + - targets: ["jaeger:8888"] + - job_name: echo + static_configs: + - targets: ["echo:9464"] + - job_name: api + static_configs: + - targets: ["api:9464"] + - job_name: connector + static_configs: + - targets: ["connector:9464"]