Skip to content

test(ldap): port the LDAP integration test from the K8s charm - #1936

Draft
marceloneppel wants to merge 11 commits into
dpe-ldap-vm-charm-migrationfrom
dpe-ldap-vm-integration-test
Draft

test(ldap): port the LDAP integration test from the K8s charm#1936
marceloneppel wants to merge 11 commits into
dpe-ldap-vm-charm-migrationfrom
dpe-ldap-vm-integration-test

Conversation

@marceloneppel

@marceloneppel marceloneppel commented Sep 2, 2026

Copy link
Copy Markdown
Member

Issue

Follows the LDAP module migration into the single kernel library (postgresql-single-kernel-library #235, #236). Stacks on #1935.

Solution

Ports the K8s charm's test_ldap.py to the VM charm: deploys the glauth-k8s stack (glauth as the LDAP server with ldaps enabled, a PostgreSQL K8s charm as its auth backend, self-signed-certificates, and traefik-k8s exposing the ldaps ingress) and validates that the operator user can still run SELECT VERSION() once the ldap and send-ca-cert relations are in place.

The test then exercises the full LDAP user flow: the ldap-map config maps the LDAP group to a PostgreSQL group (the mapped role is created first, before ldap-map is set), the LDAP user and group are created in glauth through the glauth-utils charm's apply-ldif action, and the test polls for the ldap-sync sidecar to materialise the user's role before authenticating as that LDAP user through the hba ldap line. Two pending charm-side gaps are worked around in the test until the charm covers them: the identity_access group does not yet have CONNECT on the postgres database (granted here so the auth poll can complete), and the juju snap cannot read /tmp or /var/tmp, so the LDIF is sourced from $HOME under a unique name before the scp.

Because glauth-k8s is a Kubernetes charm and this charm runs on machines, the stack runs on a separate Kubernetes Juju controller and the relations are wired as cross-controller offer/consume pairs, following the VM LDAP how-to. The test is written with jubilant directly (matching the current integration test style) and fails when the Kubernetes controller is unavailable. A spread task wraps it like the other integration tests, and the task's execute step bootstraps the Kubernetes controller through a task-scoped concierge config so no other integration job pays for it.

The only shared-code change is in the test helpers: execute_query_on_unit gains a username parameter (defaulting to operator) so the auth poll can connect as the LDAP user. No charm code changes.

Checklist

  • I have added or updated any relevant documentation.
  • I have cleaned any remaining cloud resources from my accounts.

@marceloneppel marceloneppel added the enhancement New feature, UI change, or workload upgrade label Sep 2, 2026
@github-actions github-actions Bot added the Libraries: Out of sync The charm libs used are out-of-sync label Sep 2, 2026
@marceloneppel
marceloneppel force-pushed the dpe-ldap-vm-charm-migration branch from 2da8af3 to 41ce8b3 Compare September 2, 2026 15:14
@marceloneppel
marceloneppel force-pushed the dpe-ldap-vm-integration-test branch 2 times, most recently from 08111e9 to 2cb3137 Compare September 2, 2026 15:25
@marceloneppel
marceloneppel force-pushed the dpe-ldap-vm-charm-migration branch 3 times, most recently from 65cb61c to 7a479e6 Compare September 2, 2026 17:41
@marceloneppel
marceloneppel force-pushed the dpe-ldap-vm-integration-test branch from 2cb3137 to a84cb07 Compare September 2, 2026 17:54
@marceloneppel
marceloneppel force-pushed the dpe-ldap-vm-charm-migration branch from 7a479e6 to afa933e Compare September 2, 2026 18:20
@marceloneppel
marceloneppel force-pushed the dpe-ldap-vm-integration-test branch from a84cb07 to d1de587 Compare September 2, 2026 18:20
@marceloneppel
marceloneppel force-pushed the dpe-ldap-vm-charm-migration branch from afa933e to b0b6d64 Compare September 2, 2026 18:47
@marceloneppel
marceloneppel force-pushed the dpe-ldap-vm-integration-test branch from d1de587 to dfa36f7 Compare September 2, 2026 18:48
@marceloneppel
marceloneppel force-pushed the dpe-ldap-vm-charm-migration branch from b0b6d64 to 718ac09 Compare September 2, 2026 19:32
@marceloneppel
marceloneppel force-pushed the dpe-ldap-vm-integration-test branch 8 times, most recently from dd82e75 to 7169345 Compare September 3, 2026 21:18
Ports the K8s charm's LDAP integration test to the VM charm, adapted
for the cross-controller topology: the glauth-k8s stack (glauth, its
PostgreSQL backend, self-signed-certificates, traefik) runs on a
Canonical K8s controller prepared by concierge, and the LDAP and
send-ca-cert endpoints are wired to the VM charm via cross-controller
offer/consume relations.

The test validates two things end to end:
- the operator user can still access the instance after LDAP
  enablement (the hba 'ldap' line must not break local auth), and
- a real LDAP user created through glauth-utils authenticates through
  the hba 'ldap' line once the ldap-sync sidecar materialises its
  role from the ldap-map group mapping.

The dual-provider concierge config (LXD for the charm, Canonical K8s
for the glauth stack) is inlined in the spread task's execute step so
no other integration job pays for the K8s bootstrap. The test fails
loudly when the concierge-k8s controller is unavailable instead of
silently skipping, so a missing bootstrap is never mistaken for a
pass.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
@marceloneppel
marceloneppel force-pushed the dpe-ldap-vm-integration-test branch from 7169345 to 23a54da Compare September 3, 2026 21:19
The trailing escaped quote closes the psql -tAc argument opened earlier
in the same command; removing it left an unbalanced shell quote that
crashed every diagnostic exec with 'unexpected EOF' before the auth
poll could run.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
GLAuth's bind compares the sha256 hexdigest of the presented password
against the stored passsha256; the earlier base64 form never matched,
so every LDAP bind failed with invalid credentials.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
The charm validates the ldap-map psql groups against pg_roles on
config-changed and blocks without deferring when one is missing, so the
role must exist before the mapping is set.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
The charmed-postgresql snap's psql wrapper is a Perl script that needs
POSIX.pm, which is unavailable in the juju exec environment on arm64
runners, crashing the diagnostics with 'Can't locate POSIX.pm'. Use
psycopg2 from the runner instead, matching how the operator validation
query works.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
The retry loop passed four positional arguments to
execute_query_on_unit, whose signature is (address, password, query,
database): the LDAP username landed in the password slot, the password
became the query, and 'SELECT 1;' became the database name — while the
DSN still hardcoded user='operator'. Every attempt therefore
authenticated as operator with the LDAP user's password and failed with
'password authentication failed for user "operator"'.

Add a username parameter (default operator) to execute_query_on_unit and
pass the LDAP user explicitly, and drop a duplicated log line.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
The juju snap reads /tmp and /var/tmp through a private namespace, so a
transfer sourced from either directory cannot see the local file: the
scp fails outright from /tmp and lands an empty file on the unit from
/var/tmp. apply-ldif then succeeds vacuously on an empty LDIF, the sync
has nothing to synchronise, and the auth poll never sees the role.
Source the transfer from HOME, which the snap can read.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
get_unit_address and the journal diagnostic hardcoded postgresql/0, but
re-runs on a reused model keep incrementing the unit counter after
remove-application, so the app's first unit may be /1 or higher. Resolve
the first unit of the application from the status instead.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
The charm creates the identity_access access group (NOLOGIN) but never
grants it CONNECT on the postgres database, so every hba-matched LDAP
bind fails with 'permission denied for database postgres'. Grant it in
the test until the charm-side grant lands.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
The CONNECT-grant commit accidentally repeated the CREATE ROLE
statement from the block above it, so every run fails with
DuplicateObject: role "superheros" already exists. Keep only the
GRANT CONNECT statement there.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature, UI change, or workload upgrade Libraries: Out of sync The charm libs used are out-of-sync

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant