Skip to content

Commit 5af4379

Browse files
authored
[UI] add toggle for connection pooler (#953)
* [UI] add toggle for connection pooler * remove team service logger * fix new.tag.pug and change port in Makefile
1 parent 865d5b4 commit 5af4379

11 files changed

+100
-11
lines changed

ui/Dockerfile

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
FROM alpine:3.6
22
33

4-
EXPOSE 8080
4+
EXPOSE 8081
55

66
RUN \
77
apk add --no-cache \
@@ -29,6 +29,7 @@ RUN \
2929
/var/cache/apk/*
3030

3131
COPY requirements.txt /
32+
COPY start_server.sh /
3233
RUN pip3 install -r /requirements.txt
3334

3435
COPY operator_ui /operator_ui
@@ -37,4 +38,4 @@ ARG VERSION=dev
3738
RUN sed -i "s/__version__ = .*/__version__ = '${VERSION}'/" /operator_ui/__init__.py
3839

3940
WORKDIR /
40-
ENTRYPOINT ["/usr/bin/python3", "-m", "operator_ui"]
41+
CMD ["/usr/bin/python3", "-m", "operator_ui"]

ui/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,4 @@ push:
3636
docker push "$(IMAGE):$(TAG)$(CDP_TAG)"
3737

3838
mock:
39-
docker run -it -p 8080:8080 "$(IMAGE):$(TAG)" --mock
39+
docker run -it -p 8081:8081 "$(IMAGE):$(TAG)" --mock

ui/app/src/edit.tag.pug

+1
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ edit
137137
o.spec.numberOfInstances = i.spec.numberOfInstances
138138
o.spec.enableMasterLoadBalancer = i.spec.enableMasterLoadBalancer || false
139139
o.spec.enableReplicaLoadBalancer = i.spec.enableReplicaLoadBalancer || false
140+
o.spec.enableConnectionPooler = i.spec.enableConnectionPooler || false
140141
o.spec.volume = { size: i.spec.volume.size }
141142

142143
if ('users' in i.spec && typeof i.spec.users === 'object') {

ui/app/src/new.tag.pug

+24-1
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,18 @@ new
239239
|
240240
| Enable replica ELB
241241

242+
tr
243+
td Enable Connection Pool
244+
td
245+
label
246+
input(
247+
type='checkbox'
248+
value='{ enableConnectionPooler }'
249+
onchange='{ toggleEnableConnectionPooler }'
250+
)
251+
|
252+
| Enable Connection Pool (using PGBouncer)
253+
242254
tr
243255
td Volume size
244256
td
@@ -493,6 +505,9 @@ new
493505
{{#if enableReplicaLoadBalancer}}
494506
enableReplicaLoadBalancer: true
495507
{{/if}}
508+
{{#if enableConnectionPooler}}
509+
enableConnectionPooler: true
510+
{{/if}}
496511
volume:
497512
size: "{{ volumeSize }}Gi"
498513
{{#if users}}
@@ -516,13 +531,14 @@ new
516531
- {{ odd }}/32
517532
{{/if}}
518533
534+
{{#if resourcesVisible}}
519535
resources:
520536
requests:
521537
cpu: {{ cpu.state.request.state }}m
522538
memory: {{ memory.state.request.state }}Mi
523539
limits:
524540
cpu: {{ cpu.state.limit.state }}m
525-
memory: {{ memory.state.limit.state }}Mi{{#if restoring}}
541+
memory: {{ memory.state.limit.state }}Mi{{/if}}{{#if restoring}}
526542
527543
clone:
528544
cluster: "{{ backup.state.name.state }}"
@@ -542,6 +558,7 @@ new
542558
instanceCount: this.instanceCount,
543559
enableMasterLoadBalancer: this.enableMasterLoadBalancer,
544560
enableReplicaLoadBalancer: this.enableReplicaLoadBalancer,
561+
enableConnectionPooler: this.enableConnectionPooler,
545562
volumeSize: this.volumeSize,
546563
users: this.users.valids,
547564
databases: this.databases.valids,
@@ -552,6 +569,7 @@ new
552569
memory: this.memory,
553570
backup: this.backup,
554571
namespace: this.namespace,
572+
resourcesVisible: this.config.resources_visible,
555573
restoring: this.backup.state.type.state !== 'empty',
556574
pitr: this.backup.state.type.state === 'pitr',
557575
}
@@ -598,6 +616,10 @@ new
598616
this.enableReplicaLoadBalancer = !this.enableReplicaLoadBalancer
599617
}
600618

619+
this.toggleEnableConnectionPooler = e => {
620+
this.enableConnectionPooler = !this.enableConnectionPooler
621+
}
622+
601623
this.volumeChange = e => {
602624
this.volumeSize = +e.target.value
603625
}
@@ -892,6 +914,7 @@ new
892914
this.odd = ''
893915
this.enableMasterLoadBalancer = false
894916
this.enableReplicaLoadBalancer = false
917+
this.enableConnectionPooler = false
895918

896919
this.postgresqlVersion = this.postgresqlVersion = (
897920
this.config.postgresql_versions[0]

ui/app/src/postgresql.tag.pug

+9
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ postgresql
9292
.alert.alert-success(if='{ progress.masterLabel }') PostgreSQL master available, label is attached
9393
.alert.alert-success(if='{ progress.masterLabel && progress.dnsName }') PostgreSQL ready: <strong>{ progress.dnsName }</strong>
9494

95+
.alert.alert-success(if='{ progress.pooler }') Connection pooler deployment created
96+
9597
.col-lg-3
9698
help-general(config='{ opts.config }')
9799

@@ -122,9 +124,11 @@ postgresql
122124
jQuery.get(
123125
'/postgresqls/' + this.cluster_path,
124126
).done(data => {
127+
this.progress.pooler = false
125128
this.progress.postgresql = true
126129
this.progress.postgresqlManifest = data
127130
this.progress.createdTimestamp = data.metadata.creationTimestamp
131+
this.progress.poolerEnabled = data.spec.enableConnectionPooler
128132
this.uid = this.progress.postgresqlManifest.metadata.uid
129133
this.update()
130134

@@ -160,6 +164,11 @@ postgresql
160164
this.progress.dnsName = data.metadata.name + '.' + data.metadata.namespace
161165
}
162166

167+
jQuery.get('/pooler/' + this.cluster_path).done(data => {
168+
this.progress.pooler = {"url": ""}
169+
this.update()
170+
})
171+
163172
this.update()
164173
})
165174
})

ui/manifests/deployment.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ spec:
4444
value: "http://postgres-operator:8080"
4545
- name: "OPERATOR_CLUSTER_NAME_LABEL"
4646
value: "cluster-name"
47+
- name: "RESOURCES_VISIBLE"
48+
value: "False"
4749
- name: "TARGET_NAMESPACE"
4850
value: "default"
4951
- name: "TEAMS"

ui/manifests/ui-service-account-rbac.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ rules:
3939
- apiGroups:
4040
- apps
4141
resources:
42+
- deployments
4243
- statefulsets
4344
verbs:
4445
- get

ui/operator_ui/main.py

+32-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
from flask_oauthlib.client import OAuth
2626
from functools import wraps
2727
from gevent import sleep, spawn
28-
from gevent.wsgi import WSGIServer
28+
from gevent.pywsgi import WSGIServer
2929
from jq import jq
3030
from json import dumps, loads
3131
from logging import DEBUG, ERROR, INFO, basicConfig, exception, getLogger
@@ -44,6 +44,7 @@
4444
create_postgresql,
4545
read_basebackups,
4646
read_namespaces,
47+
read_pooler,
4748
read_pods,
4849
read_postgresql,
4950
read_postgresqls,
@@ -80,6 +81,7 @@
8081
OPERATOR_UI_CONFIG = getenv('OPERATOR_UI_CONFIG', '{}')
8182
OPERATOR_UI_MAINTENANCE_CHECK = getenv('OPERATOR_UI_MAINTENANCE_CHECK', '{}')
8283
READ_ONLY_MODE = getenv('READ_ONLY_MODE', False) in [True, 'true']
84+
RESOURCES_VISIBLE = getenv('RESOURCES_VISIBLE', True)
8385
SPILO_S3_BACKUP_PREFIX = getenv('SPILO_S3_BACKUP_PREFIX', 'spilo/')
8486
SUPERUSER_TEAM = getenv('SUPERUSER_TEAM', 'acid')
8587
TARGET_NAMESPACE = getenv('TARGET_NAMESPACE')
@@ -312,6 +314,7 @@ def index():
312314
def get_config():
313315
config = loads(OPERATOR_UI_CONFIG) or DEFAULT_UI_CONFIG
314316
config['read_only_mode'] = READ_ONLY_MODE
317+
config['resources_visible'] = RESOURCES_VISIBLE
315318
config['superuser_team'] = SUPERUSER_TEAM
316319
config['target_namespace'] = TARGET_NAMESPACE
317320

@@ -397,6 +400,22 @@ def get_service(namespace: str, cluster: str):
397400
)
398401

399402

403+
@app.route('/pooler/<namespace>/<cluster>')
404+
@authorize
405+
def get_list_poolers(namespace: str, cluster: str):
406+
407+
if TARGET_NAMESPACE not in ['', '*', namespace]:
408+
return wrong_namespace()
409+
410+
return respond(
411+
read_pooler(
412+
get_cluster(),
413+
namespace,
414+
"{}-pooler".format(cluster),
415+
),
416+
)
417+
418+
400419
@app.route('/statefulsets/<namespace>/<cluster>')
401420
@authorize
402421
def get_list_clusters(namespace: str, cluster: str):
@@ -587,6 +606,17 @@ def update_postgresql(namespace: str, cluster: str):
587606

588607
spec['volume'] = {'size': size}
589608

609+
if 'enableConnectionPooler' in postgresql['spec']:
610+
cp = postgresql['spec']['enableConnectionPooler']
611+
if not cp:
612+
if 'enableConnectionPooler' in o['spec']:
613+
del o['spec']['enableConnectionPooler']
614+
else:
615+
spec['enableConnectionPooler'] = True
616+
else:
617+
if 'enableConnectionPooler' in o['spec']:
618+
del o['spec']['enableConnectionPooler']
619+
590620
if 'enableReplicaLoadBalancer' in postgresql['spec']:
591621
rlb = postgresql['spec']['enableReplicaLoadBalancer']
592622
if not rlb:
@@ -1006,7 +1036,7 @@ def init_cluster():
10061036
def main(port, secret_key, debug, clusters: list):
10071037
global TARGET_NAMESPACE
10081038

1009-
basicConfig(level=DEBUG if debug else INFO)
1039+
basicConfig(stream=sys.stdout, level=(DEBUG if debug else INFO), format='%(asctime)s %(levelname)s: %(message)s',)
10101040

10111041
init_cluster()
10121042

ui/operator_ui/spiloutils.py

+24-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from boto3 import client
22
from datetime import datetime, timezone
33
from furl import furl
4-
from json import dumps
4+
from json import dumps, loads
55
from logging import getLogger
66
from os import environ, getenv
77
from requests import Session
@@ -18,6 +18,15 @@
1818

1919
OPERATOR_CLUSTER_NAME_LABEL = getenv('OPERATOR_CLUSTER_NAME_LABEL', 'cluster-name')
2020

21+
COMMON_CLUSTER_LABEL = getenv('COMMON_CLUSTER_LABEL', '{"application":"spilo"}')
22+
COMMON_POOLER_LABEL = getenv('COMMONG_POOLER_LABEL', '{"application":"db-connection-pooler"}')
23+
24+
logger.info("Common Cluster Label: {}".format(COMMON_CLUSTER_LABEL))
25+
logger.info("Common Pooler Label: {}".format(COMMON_POOLER_LABEL))
26+
27+
COMMON_CLUSTER_LABEL = loads(COMMON_CLUSTER_LABEL)
28+
COMMON_POOLER_LABEL = loads(COMMON_POOLER_LABEL)
29+
2130

2231
def request(cluster, path, **kwargs):
2332
if 'timeout' not in kwargs:
@@ -85,6 +94,7 @@ def resource_api_version(resource_type):
8594
return {
8695
'postgresqls': 'apis/acid.zalan.do/v1',
8796
'statefulsets': 'apis/apps/v1',
97+
'deployments': 'apis/apps/v1',
8898
}.get(resource_type, 'api/v1')
8999

90100

@@ -149,7 +159,7 @@ def read_pod(cluster, namespace, resource_name):
149159
resource_type='pods',
150160
namespace=namespace,
151161
resource_name=resource_name,
152-
label_selector={'application': 'spilo'},
162+
label_selector=COMMON_CLUSTER_LABEL,
153163
)
154164

155165

@@ -159,7 +169,17 @@ def read_service(cluster, namespace, resource_name):
159169
resource_type='services',
160170
namespace=namespace,
161171
resource_name=resource_name,
162-
label_selector={'application': 'spilo'},
172+
label_selector=COMMON_CLUSTER_LABEL,
173+
)
174+
175+
176+
def read_pooler(cluster, namespace, resource_name):
177+
return kubernetes_get(
178+
cluster=cluster,
179+
resource_type='deployments',
180+
namespace=namespace,
181+
resource_name=resource_name,
182+
label_selector=COMMON_POOLER_LABEL,
163183
)
164184

165185

@@ -169,7 +189,7 @@ def read_statefulset(cluster, namespace, resource_name):
169189
resource_type='statefulsets',
170190
namespace=namespace,
171191
resource_name=resource_name,
172-
label_selector={'application': 'spilo'},
192+
label_selector=COMMON_CLUSTER_LABEL,
173193
)
174194

175195

ui/requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Flask-OAuthlib==0.9.5
2-
Flask==1.1.1
2+
Flask==1.1.2
33
backoff==1.8.1
44
boto3==1.10.4
55
boto==2.49.0

ui/start_server.sh

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/bash
2+
/usr/bin/python3 -m operator_ui

0 commit comments

Comments
 (0)