diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..5cb2cf6 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,39 @@ +# Repository Guidelines + +## Project Structure & Module Organization + +This is a Go Prometheus exporter for OpenStack database metrics. The entrypoint is `cmd/openstack-database-exporter/main.go`. Collector code lives in `internal/collector//`, shared database and DSN logic in `internal/db/`, and shared test helpers in `internal/testutil/`. SQL source files are grouped by OpenStack service under `sql//` with `schema.sql`, `queries.sql`, and optional `indexes.sql` or `prereqs.sql`. Files under `internal/db//` are generated by `sqlc`; update the SQL inputs instead of editing generated Go directly. + +## Build, Test, and Development Commands + +- `go build -o /dev/null ./cmd/openstack-database-exporter`: compile the exporter, matching CI. +- `go run ./cmd/openstack-database-exporter --help`: inspect runtime flags and supported database URL environment variables. +- `go test -count=1 -short -race ./...`: run the unit test suite used by CI. +- `go test -v -count=1 -race -tags integration -timeout 15m ./...`: run container-backed integration tests; Docker must be available. +- `sqlc generate`: regenerate `internal/db//` after changing SQL definitions. +- `docker build -t openstack-database-exporter .`: build the scratch-based runtime image. + +## Coding Style & Naming Conventions + +Use standard Go formatting (`gofmt`) and keep packages lowercase. Follow the existing service-oriented layout: service packages such as `cinder`, `nova`, and `neutron` contain collectors and tests for that service. Prefer table-driven tests and explicit Prometheus metric comparisons, as seen in existing collector tests. Metric names should continue the `openstack__` pattern. + +## Testing Guidelines + +Unit tests use `testing`, `go-sqlmock`, `testify`, and Prometheus `testutil`; name files `*_test.go` and tests `Test`. Integration tests use the `integration` build tag and `testcontainers-go` with MariaDB 11; name them `TestIntegration_` where practical. Set `SKIP_INTEGRATION=1` only when intentionally skipping tagged integration tests. + +## Commit & Pull Request Guidelines + +Recent history mostly follows Conventional Commit subjects such as `fix: ...`, `feat: ...`, `ci: ...`, and `chore(deps): ...`; use the same concise imperative style. Pull requests should describe the exporter behavior changed, list affected services or metrics, link related issues, and note any SQL or generated-code updates. Run the relevant unit, integration, build, and `sqlc generate` checks before requesting review. + +## Local Configuration & Security + +Configure database access with oslo.db-style MySQL URLs in environment variables. Keep examples generic and never commit real credentials, endpoint names, local `exporter.sh` values, logs, or captured metric output. + +```sh +export NOVA_DATABASE_URL="mysql+pymysql://:@:/nova" +export NOVA_API_DATABASE_URL="mysql+pymysql://:@:/nova_api" +export KEYSTONE_DATABASE_URL="mysql+pymysql://:@:/keystone" +export PLACEMENT_DATABASE_URL="mysql+pymysql://:@:/placement" +``` + +Set only the service URLs needed for the collectors under test. diff --git a/internal/collector/cinder/integration_test.go b/internal/collector/cinder/integration_test.go index a804d68..e68f700 100644 --- a/internal/collector/cinder/integration_test.go +++ b/internal/collector/cinder/integration_test.go @@ -44,8 +44,9 @@ func TestIntegration_VolumesCollector(t *testing.T) { ('vol-001', 'boot-vol', 40, 'in-use', 'nova', 1, 'proj-001', 'user-001', 'vtype-001', 0), ('vol-002', 'data-vol', 100, 'available', 'nova', 0, 'proj-001', 'user-001', 'vtype-002', 0), ('vol-003', 'deleted-vol', 50, 'deleted', 'nova', 0, 'proj-002', 'user-002', 'vtype-001', 1)`, - `INSERT INTO volume_attachment (id, volume_id, instance_uuid, deleted) VALUES - ('att-001', 'vol-001', 'server-001', 0)`, + `INSERT INTO volume_attachment (id, volume_id, instance_uuid, deleted, attach_status) VALUES + ('att-001', 'vol-001', 'server-001', 0, 'attached'), + ('att-002', 'vol-001', 'server-001', 0, 'detached')`, ) collector := NewVolumesCollector(db, logger) diff --git a/internal/db/cinder/queries.sql.go b/internal/db/cinder/queries.sql.go index 429a2d6..defeb01 100644 --- a/internal/db/cinder/queries.sql.go +++ b/internal/db/cinder/queries.sql.go @@ -137,7 +137,7 @@ SELECT FROM volumes v USE INDEX (volumes_service_uuid_idx) LEFT JOIN volume_types vt ON v.volume_type_id = vt.id - LEFT JOIN volume_attachment va ON v.id = va.volume_id AND va.deleted = 0 + LEFT JOIN volume_attachment va ON v.id = va.volume_id AND va.deleted = 0 AND va.attach_status = 'attached' WHERE (v.service_uuid IS NULL OR v.service_uuid IS NOT NULL) AND v.deleted = 0 diff --git a/sql/cinder/queries.sql b/sql/cinder/queries.sql index d432fbb..7cc3fe4 100644 --- a/sql/cinder/queries.sql +++ b/sql/cinder/queries.sql @@ -86,7 +86,7 @@ SELECT FROM volumes v USE INDEX (volumes_service_uuid_idx) LEFT JOIN volume_types vt ON v.volume_type_id = vt.id - LEFT JOIN volume_attachment va ON v.id = va.volume_id AND va.deleted = 0 + LEFT JOIN volume_attachment va ON v.id = va.volume_id AND va.deleted = 0 AND va.attach_status = 'attached' WHERE (v.service_uuid IS NULL OR v.service_uuid IS NOT NULL) AND v.deleted = 0;