[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
This commit is contained in:
parent
865d5b41a7
commit
5af4379118
|
|
@ -1,7 +1,7 @@
|
|||
FROM alpine:3.6
|
||||
MAINTAINER team-acid@zalando.de
|
||||
|
||||
EXPOSE 8080
|
||||
EXPOSE 8081
|
||||
|
||||
RUN \
|
||||
apk add --no-cache \
|
||||
|
|
@ -29,6 +29,7 @@ RUN \
|
|||
/var/cache/apk/*
|
||||
|
||||
COPY requirements.txt /
|
||||
COPY start_server.sh /
|
||||
RUN pip3 install -r /requirements.txt
|
||||
|
||||
COPY operator_ui /operator_ui
|
||||
|
|
@ -37,4 +38,4 @@ ARG VERSION=dev
|
|||
RUN sed -i "s/__version__ = .*/__version__ = '${VERSION}'/" /operator_ui/__init__.py
|
||||
|
||||
WORKDIR /
|
||||
ENTRYPOINT ["/usr/bin/python3", "-m", "operator_ui"]
|
||||
CMD ["/usr/bin/python3", "-m", "operator_ui"]
|
||||
|
|
|
|||
|
|
@ -36,4 +36,4 @@ push:
|
|||
docker push "$(IMAGE):$(TAG)$(CDP_TAG)"
|
||||
|
||||
mock:
|
||||
docker run -it -p 8080:8080 "$(IMAGE):$(TAG)" --mock
|
||||
docker run -it -p 8081:8081 "$(IMAGE):$(TAG)" --mock
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ edit
|
|||
o.spec.numberOfInstances = i.spec.numberOfInstances
|
||||
o.spec.enableMasterLoadBalancer = i.spec.enableMasterLoadBalancer || false
|
||||
o.spec.enableReplicaLoadBalancer = i.spec.enableReplicaLoadBalancer || false
|
||||
o.spec.enableConnectionPooler = i.spec.enableConnectionPooler || false
|
||||
o.spec.volume = { size: i.spec.volume.size }
|
||||
|
||||
if ('users' in i.spec && typeof i.spec.users === 'object') {
|
||||
|
|
|
|||
|
|
@ -239,6 +239,18 @@ new
|
|||
|
|
||||
| Enable replica ELB
|
||||
|
||||
tr
|
||||
td Enable Connection Pool
|
||||
td
|
||||
label
|
||||
input(
|
||||
type='checkbox'
|
||||
value='{ enableConnectionPooler }'
|
||||
onchange='{ toggleEnableConnectionPooler }'
|
||||
)
|
||||
|
|
||||
| Enable Connection Pool (using PGBouncer)
|
||||
|
||||
tr
|
||||
td Volume size
|
||||
td
|
||||
|
|
@ -493,6 +505,9 @@ new
|
|||
{{#if enableReplicaLoadBalancer}}
|
||||
enableReplicaLoadBalancer: true
|
||||
{{/if}}
|
||||
{{#if enableConnectionPooler}}
|
||||
enableConnectionPooler: true
|
||||
{{/if}}
|
||||
volume:
|
||||
size: "{{ volumeSize }}Gi"
|
||||
{{#if users}}
|
||||
|
|
@ -516,13 +531,14 @@ new
|
|||
- {{ odd }}/32
|
||||
{{/if}}
|
||||
|
||||
{{#if resourcesVisible}}
|
||||
resources:
|
||||
requests:
|
||||
cpu: {{ cpu.state.request.state }}m
|
||||
memory: {{ memory.state.request.state }}Mi
|
||||
limits:
|
||||
cpu: {{ cpu.state.limit.state }}m
|
||||
memory: {{ memory.state.limit.state }}Mi{{#if restoring}}
|
||||
memory: {{ memory.state.limit.state }}Mi{{/if}}{{#if restoring}}
|
||||
|
||||
clone:
|
||||
cluster: "{{ backup.state.name.state }}"
|
||||
|
|
@ -542,6 +558,7 @@ new
|
|||
instanceCount: this.instanceCount,
|
||||
enableMasterLoadBalancer: this.enableMasterLoadBalancer,
|
||||
enableReplicaLoadBalancer: this.enableReplicaLoadBalancer,
|
||||
enableConnectionPooler: this.enableConnectionPooler,
|
||||
volumeSize: this.volumeSize,
|
||||
users: this.users.valids,
|
||||
databases: this.databases.valids,
|
||||
|
|
@ -552,6 +569,7 @@ new
|
|||
memory: this.memory,
|
||||
backup: this.backup,
|
||||
namespace: this.namespace,
|
||||
resourcesVisible: this.config.resources_visible,
|
||||
restoring: this.backup.state.type.state !== 'empty',
|
||||
pitr: this.backup.state.type.state === 'pitr',
|
||||
}
|
||||
|
|
@ -598,6 +616,10 @@ new
|
|||
this.enableReplicaLoadBalancer = !this.enableReplicaLoadBalancer
|
||||
}
|
||||
|
||||
this.toggleEnableConnectionPooler = e => {
|
||||
this.enableConnectionPooler = !this.enableConnectionPooler
|
||||
}
|
||||
|
||||
this.volumeChange = e => {
|
||||
this.volumeSize = +e.target.value
|
||||
}
|
||||
|
|
@ -892,6 +914,7 @@ new
|
|||
this.odd = ''
|
||||
this.enableMasterLoadBalancer = false
|
||||
this.enableReplicaLoadBalancer = false
|
||||
this.enableConnectionPooler = false
|
||||
|
||||
this.postgresqlVersion = this.postgresqlVersion = (
|
||||
this.config.postgresql_versions[0]
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ postgresql
|
|||
.alert.alert-success(if='{ progress.masterLabel }') PostgreSQL master available, label is attached
|
||||
.alert.alert-success(if='{ progress.masterLabel && progress.dnsName }') PostgreSQL ready: <strong>{ progress.dnsName }</strong>
|
||||
|
||||
.alert.alert-success(if='{ progress.pooler }') Connection pooler deployment created
|
||||
|
||||
.col-lg-3
|
||||
help-general(config='{ opts.config }')
|
||||
|
||||
|
|
@ -122,9 +124,11 @@ postgresql
|
|||
jQuery.get(
|
||||
'/postgresqls/' + this.cluster_path,
|
||||
).done(data => {
|
||||
this.progress.pooler = false
|
||||
this.progress.postgresql = true
|
||||
this.progress.postgresqlManifest = data
|
||||
this.progress.createdTimestamp = data.metadata.creationTimestamp
|
||||
this.progress.poolerEnabled = data.spec.enableConnectionPooler
|
||||
this.uid = this.progress.postgresqlManifest.metadata.uid
|
||||
this.update()
|
||||
|
||||
|
|
@ -160,6 +164,11 @@ postgresql
|
|||
this.progress.dnsName = data.metadata.name + '.' + data.metadata.namespace
|
||||
}
|
||||
|
||||
jQuery.get('/pooler/' + this.cluster_path).done(data => {
|
||||
this.progress.pooler = {"url": ""}
|
||||
this.update()
|
||||
})
|
||||
|
||||
this.update()
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ spec:
|
|||
value: "http://postgres-operator:8080"
|
||||
- name: "OPERATOR_CLUSTER_NAME_LABEL"
|
||||
value: "cluster-name"
|
||||
- name: "RESOURCES_VISIBLE"
|
||||
value: "False"
|
||||
- name: "TARGET_NAMESPACE"
|
||||
value: "default"
|
||||
- name: "TEAMS"
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ rules:
|
|||
- apiGroups:
|
||||
- apps
|
||||
resources:
|
||||
- deployments
|
||||
- statefulsets
|
||||
verbs:
|
||||
- get
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ from flask import (
|
|||
from flask_oauthlib.client import OAuth
|
||||
from functools import wraps
|
||||
from gevent import sleep, spawn
|
||||
from gevent.wsgi import WSGIServer
|
||||
from gevent.pywsgi import WSGIServer
|
||||
from jq import jq
|
||||
from json import dumps, loads
|
||||
from logging import DEBUG, ERROR, INFO, basicConfig, exception, getLogger
|
||||
|
|
@ -44,6 +44,7 @@ from .spiloutils import (
|
|||
create_postgresql,
|
||||
read_basebackups,
|
||||
read_namespaces,
|
||||
read_pooler,
|
||||
read_pods,
|
||||
read_postgresql,
|
||||
read_postgresqls,
|
||||
|
|
@ -80,6 +81,7 @@ OPERATOR_CLUSTER_NAME_LABEL = getenv('OPERATOR_CLUSTER_NAME_LABEL', 'cluster-nam
|
|||
OPERATOR_UI_CONFIG = getenv('OPERATOR_UI_CONFIG', '{}')
|
||||
OPERATOR_UI_MAINTENANCE_CHECK = getenv('OPERATOR_UI_MAINTENANCE_CHECK', '{}')
|
||||
READ_ONLY_MODE = getenv('READ_ONLY_MODE', False) in [True, 'true']
|
||||
RESOURCES_VISIBLE = getenv('RESOURCES_VISIBLE', True)
|
||||
SPILO_S3_BACKUP_PREFIX = getenv('SPILO_S3_BACKUP_PREFIX', 'spilo/')
|
||||
SUPERUSER_TEAM = getenv('SUPERUSER_TEAM', 'acid')
|
||||
TARGET_NAMESPACE = getenv('TARGET_NAMESPACE')
|
||||
|
|
@ -312,6 +314,7 @@ DEFAULT_UI_CONFIG = {
|
|||
def get_config():
|
||||
config = loads(OPERATOR_UI_CONFIG) or DEFAULT_UI_CONFIG
|
||||
config['read_only_mode'] = READ_ONLY_MODE
|
||||
config['resources_visible'] = RESOURCES_VISIBLE
|
||||
config['superuser_team'] = SUPERUSER_TEAM
|
||||
config['target_namespace'] = TARGET_NAMESPACE
|
||||
|
||||
|
|
@ -397,6 +400,22 @@ def get_service(namespace: str, cluster: str):
|
|||
)
|
||||
|
||||
|
||||
@app.route('/pooler/<namespace>/<cluster>')
|
||||
@authorize
|
||||
def get_list_poolers(namespace: str, cluster: str):
|
||||
|
||||
if TARGET_NAMESPACE not in ['', '*', namespace]:
|
||||
return wrong_namespace()
|
||||
|
||||
return respond(
|
||||
read_pooler(
|
||||
get_cluster(),
|
||||
namespace,
|
||||
"{}-pooler".format(cluster),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@app.route('/statefulsets/<namespace>/<cluster>')
|
||||
@authorize
|
||||
def get_list_clusters(namespace: str, cluster: str):
|
||||
|
|
@ -587,6 +606,17 @@ def update_postgresql(namespace: str, cluster: str):
|
|||
|
||||
spec['volume'] = {'size': size}
|
||||
|
||||
if 'enableConnectionPooler' in postgresql['spec']:
|
||||
cp = postgresql['spec']['enableConnectionPooler']
|
||||
if not cp:
|
||||
if 'enableConnectionPooler' in o['spec']:
|
||||
del o['spec']['enableConnectionPooler']
|
||||
else:
|
||||
spec['enableConnectionPooler'] = True
|
||||
else:
|
||||
if 'enableConnectionPooler' in o['spec']:
|
||||
del o['spec']['enableConnectionPooler']
|
||||
|
||||
if 'enableReplicaLoadBalancer' in postgresql['spec']:
|
||||
rlb = postgresql['spec']['enableReplicaLoadBalancer']
|
||||
if not rlb:
|
||||
|
|
@ -1006,7 +1036,7 @@ def init_cluster():
|
|||
def main(port, secret_key, debug, clusters: list):
|
||||
global TARGET_NAMESPACE
|
||||
|
||||
basicConfig(level=DEBUG if debug else INFO)
|
||||
basicConfig(stream=sys.stdout, level=(DEBUG if debug else INFO), format='%(asctime)s %(levelname)s: %(message)s',)
|
||||
|
||||
init_cluster()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from boto3 import client
|
||||
from datetime import datetime, timezone
|
||||
from furl import furl
|
||||
from json import dumps
|
||||
from json import dumps, loads
|
||||
from logging import getLogger
|
||||
from os import environ, getenv
|
||||
from requests import Session
|
||||
|
|
@ -18,6 +18,15 @@ session = Session()
|
|||
|
||||
OPERATOR_CLUSTER_NAME_LABEL = getenv('OPERATOR_CLUSTER_NAME_LABEL', 'cluster-name')
|
||||
|
||||
COMMON_CLUSTER_LABEL = getenv('COMMON_CLUSTER_LABEL', '{"application":"spilo"}')
|
||||
COMMON_POOLER_LABEL = getenv('COMMONG_POOLER_LABEL', '{"application":"db-connection-pooler"}')
|
||||
|
||||
logger.info("Common Cluster Label: {}".format(COMMON_CLUSTER_LABEL))
|
||||
logger.info("Common Pooler Label: {}".format(COMMON_POOLER_LABEL))
|
||||
|
||||
COMMON_CLUSTER_LABEL = loads(COMMON_CLUSTER_LABEL)
|
||||
COMMON_POOLER_LABEL = loads(COMMON_POOLER_LABEL)
|
||||
|
||||
|
||||
def request(cluster, path, **kwargs):
|
||||
if 'timeout' not in kwargs:
|
||||
|
|
@ -85,6 +94,7 @@ def resource_api_version(resource_type):
|
|||
return {
|
||||
'postgresqls': 'apis/acid.zalan.do/v1',
|
||||
'statefulsets': 'apis/apps/v1',
|
||||
'deployments': 'apis/apps/v1',
|
||||
}.get(resource_type, 'api/v1')
|
||||
|
||||
|
||||
|
|
@ -149,7 +159,7 @@ def read_pod(cluster, namespace, resource_name):
|
|||
resource_type='pods',
|
||||
namespace=namespace,
|
||||
resource_name=resource_name,
|
||||
label_selector={'application': 'spilo'},
|
||||
label_selector=COMMON_CLUSTER_LABEL,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -159,7 +169,17 @@ def read_service(cluster, namespace, resource_name):
|
|||
resource_type='services',
|
||||
namespace=namespace,
|
||||
resource_name=resource_name,
|
||||
label_selector={'application': 'spilo'},
|
||||
label_selector=COMMON_CLUSTER_LABEL,
|
||||
)
|
||||
|
||||
|
||||
def read_pooler(cluster, namespace, resource_name):
|
||||
return kubernetes_get(
|
||||
cluster=cluster,
|
||||
resource_type='deployments',
|
||||
namespace=namespace,
|
||||
resource_name=resource_name,
|
||||
label_selector=COMMON_POOLER_LABEL,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -169,7 +189,7 @@ def read_statefulset(cluster, namespace, resource_name):
|
|||
resource_type='statefulsets',
|
||||
namespace=namespace,
|
||||
resource_name=resource_name,
|
||||
label_selector={'application': 'spilo'},
|
||||
label_selector=COMMON_CLUSTER_LABEL,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
Flask-OAuthlib==0.9.5
|
||||
Flask==1.1.1
|
||||
Flask==1.1.2
|
||||
backoff==1.8.1
|
||||
boto3==1.10.4
|
||||
boto==2.49.0
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
#!/bin/bash
|
||||
/usr/bin/python3 -m operator_ui
|
||||
Loading…
Reference in New Issue