Skip to content

Commit 7da8997

Browse files
committed
Adding user management for standalone pgAdmin. When user is present in spec, reconcile loop will attempt to add or update it in pgAdmin as necessary, and the users.json file we keep in the pgadmin secret will be updated accordingly. Users removed from spec will be removed from users.json, but will not be deleted from pgAdmin. Add go and kuttl tests for this functionality. Move pod_client.go to controller/runtime package. Move PGADMIN_DIR value to a const.
1 parent a8b3fe2 commit 7da8997

22 files changed

+1209
-18
lines changed

config/crd/bases/postgres-operator.crunchydata.com_pgadmins.yaml

+36-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ spec:
2020
- name: v1beta1
2121
schema:
2222
openAPIV3Schema:
23-
description: PGAdmin is the Schema for the pgadmins API
23+
description: PGAdmin is the Schema for the PGAdmin API
2424
properties:
2525
apiVersion:
2626
description: 'APIVersion defines the versioned schema of this representation
@@ -1442,16 +1442,40 @@ spec:
14421442
type: string
14431443
type: object
14441444
type: array
1445+
users:
1446+
description: pgAdmin users that are managed via the PGAdmin spec.
1447+
Users can still be added via the pgAdmin GUI, but those users will
1448+
not show up here.
1449+
items:
1450+
properties:
1451+
role:
1452+
description: Role determines whether the user has admin privileges
1453+
or not. Defaults to User. Valid options are Administrator
1454+
and User.
1455+
enum:
1456+
- Administrator
1457+
- User
1458+
type: string
1459+
username:
1460+
description: The username for User in pgAdmin. Must be unique
1461+
in the pgAdmin's users list.
1462+
type: string
1463+
required:
1464+
- username
1465+
type: object
1466+
type: array
1467+
x-kubernetes-list-map-keys:
1468+
- username
1469+
x-kubernetes-list-type: map
14451470
required:
14461471
- dataVolumeClaimSpec
14471472
type: object
14481473
status:
14491474
description: PGAdminStatus defines the observed state of PGAdmin
14501475
properties:
14511476
conditions:
1452-
description: 'conditions represent the observations of pgadmin''s
1453-
current state. Known .status.conditions.type are: "PersistentVolumeResizing",
1454-
"Progressing", "ProxyAvailable"'
1477+
description: 'conditions represent the observations of pgAdmin''s
1478+
current state. Known .status.conditions.type is: "PersistentVolumeResizing"'
14551479
items:
14561480
description: "Condition contains details for one aspect of the current
14571481
state of this API Resource. --- This struct is intended for direct
@@ -1522,6 +1546,14 @@ spec:
15221546
x-kubernetes-list-map-keys:
15231547
- type
15241548
x-kubernetes-list-type: map
1549+
imageSHA:
1550+
description: ImageSHA represents the image SHA for the container running
1551+
pgAdmin.
1552+
type: string
1553+
majorVersion:
1554+
description: MajorVersion represents the major version of the running
1555+
pgAdmin.
1556+
type: integer
15251557
observedGeneration:
15261558
description: observedGeneration represents the .metadata.generation
15271559
on which the status was based.

internal/controller/postgrescluster/controller.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import (
4343
"sigs.k8s.io/controller-runtime/pkg/source"
4444

4545
"github.com/crunchydata/postgres-operator/internal/config"
46+
"github.com/crunchydata/postgres-operator/internal/controller/runtime"
4647
"github.com/crunchydata/postgres-operator/internal/logging"
4748
"github.com/crunchydata/postgres-operator/internal/pgaudit"
4849
"github.com/crunchydata/postgres-operator/internal/pgbackrest"
@@ -451,7 +452,7 @@ func (r *Reconciler) setOwnerReference(
451452
func (r *Reconciler) SetupWithManager(mgr manager.Manager) error {
452453
if r.PodExec == nil {
453454
var err error
454-
r.PodExec, err = newPodExecutor(mgr.GetConfig())
455+
r.PodExec, err = runtime.NewPodExecutor(mgr.GetConfig())
455456
if err != nil {
456457
return err
457458
}

internal/controller/postgrescluster/pod_client.go renamed to internal/controller/runtime/pod_client.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
limitations under the License.
1414
*/
1515

16-
package postgrescluster
16+
package runtime
1717

1818
import (
1919
"io"
@@ -41,7 +41,7 @@ func newPodClient(config *rest.Config) (rest.Interface, error) {
4141

4242
// +kubebuilder:rbac:groups="",resources="pods/exec",verbs={create}
4343

44-
func newPodExecutor(config *rest.Config) (podExecutor, error) {
44+
func NewPodExecutor(config *rest.Config) (podExecutor, error) {
4545
client, err := newPodClient(config)
4646

4747
return func(

internal/controller/standalone_pgadmin/config.go

+3
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,7 @@ const (
2323

2424
// Port address used to define pod and service
2525
pgAdminPort = 5050
26+
27+
// Directory for pgAdmin in container
28+
pgAdminDir = "/usr/local/lib/python3.11/site-packages/pgadmin4"
2629
)

internal/controller/standalone_pgadmin/controller.go

+19-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package standalone_pgadmin
1616

1717
import (
1818
"context"
19+
"io"
1920

2021
appsv1 "k8s.io/api/apps/v1"
2122
corev1 "k8s.io/api/core/v1"
@@ -29,14 +30,19 @@ import (
2930
"sigs.k8s.io/controller-runtime/pkg/handler"
3031
"sigs.k8s.io/controller-runtime/pkg/source"
3132

33+
controllerruntime "github.com/crunchydata/postgres-operator/internal/controller/runtime"
3234
"github.com/crunchydata/postgres-operator/internal/logging"
3335
"github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1"
3436
)
3537

3638
// PGAdminReconciler reconciles a PGAdmin object
3739
type PGAdminReconciler struct {
3840
client.Client
39-
Owner client.FieldOwner
41+
Owner client.FieldOwner
42+
PodExec func(
43+
namespace, pod, container string,
44+
stdin io.Reader, stdout, stderr io.Writer, command ...string,
45+
) error
4046
Recorder record.EventRecorder
4147
IsOpenShift bool
4248
}
@@ -51,6 +57,14 @@ type PGAdminReconciler struct {
5157
//
5258
// TODO(tjmoore4): This function is duplicated from a version that takes a PostgresCluster object.
5359
func (r *PGAdminReconciler) SetupWithManager(mgr ctrl.Manager) error {
60+
if r.PodExec == nil {
61+
var err error
62+
r.PodExec, err = controllerruntime.NewPodExecutor(mgr.GetConfig())
63+
if err != nil {
64+
return err
65+
}
66+
}
67+
5468
return ctrl.NewControllerManagedBy(mgr).
5569
For(&v1beta1.PGAdmin{}).
5670
Owns(&corev1.ConfigMap{}).
@@ -146,12 +160,15 @@ func (r *PGAdminReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
146160
if err == nil {
147161
err = r.reconcilePGAdminStatefulSet(ctx, pgAdmin, configmap, dataVolume)
148162
}
163+
if err == nil {
164+
err = r.reconcilePGAdminUsers(ctx, pgAdmin)
165+
}
149166

150167
if err == nil {
151168
// at this point everything reconciled successfully, and we can update the
152169
// observedGeneration
153170
pgAdmin.Status.ObservedGeneration = pgAdmin.GetGeneration()
154-
log.V(1).Info("reconciled cluster")
171+
log.V(1).Info("reconciled pgadmin")
155172
}
156173

157174
return ctrl.Result{}, err

internal/controller/standalone_pgadmin/pod.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ func startupScript(pgadmin *v1beta1.PGAdmin) []string {
276276
// - https://www.pgadmin.org/docs/pgadmin4/development/server_deployment.html#standalone-gunicorn-configuration
277277
// - https://docs.gunicorn.org/en/latest/configure.html
278278
var startScript = fmt.Sprintf(`
279-
PGADMIN_DIR=/usr/local/lib/python3.11/site-packages/pgadmin4
279+
PGADMIN_DIR=%s
280280
APP_RELEASE=$(cd $PGADMIN_DIR && python3 -c "import config; print(config.APP_RELEASE)")
281281
282282
echo "Running pgAdmin4 Setup"
@@ -303,7 +303,7 @@ loadServerCommand() {
303303
fi
304304
}
305305
loadServerCommand
306-
`, setupCommandV7, setupCommandV8, startCommandV7, startCommandV8, loadServerCommandV7, loadServerCommandV8)
306+
`, pgAdminDir, setupCommandV7, setupCommandV8, startCommandV7, startCommandV8, loadServerCommandV7, loadServerCommandV8)
307307

308308
// Use a Bash loop to periodically check:
309309
// 1. the mtime of the mounted configuration volume for shared/discovered servers.

internal/controller/standalone_pgadmin/secret.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,11 @@ func secret(pgadmin *v1beta1.PGAdmin, existing *corev1.Secret) (*corev1.Secret,
7272
})
7373

7474
intent.Data = make(map[string][]byte)
75-
intent.StringData = make(map[string]string)
7675

7776
// The username format is hardcoded,
7877
// but append the full username to the secret for visibility
79-
intent.StringData["username"] = fmt.Sprintf("admin@%s.%s.svc",
80-
pgadmin.Name, pgadmin.Namespace)
78+
intent.Data["username"] = []byte(fmt.Sprintf("admin@%s.%s.svc",
79+
pgadmin.Name, pgadmin.Namespace))
8180

8281
// Copy existing password into the intent
8382
if existing.Data != nil {
@@ -93,5 +92,10 @@ func secret(pgadmin *v1beta1.PGAdmin, existing *corev1.Secret) (*corev1.Secret,
9392
intent.Data["password"] = []byte(password)
9493
}
9594

95+
// Copy existing user data into the intent
96+
if existing.Data["users.json"] != nil {
97+
intent.Data["users.json"] = existing.Data["users.json"]
98+
}
99+
96100
return intent, nil
97101
}

0 commit comments

Comments
 (0)