[UI] support Postgres version and pod resource changes + adding IOPS and throughput config options (#1824)

This commit is contained in:
Felix Kunde 2022-03-25 10:03:20 +01:00 committed by GitHub
parent 654d22d04a
commit d6641a9b0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 137 additions and 14 deletions

View File

@ -126,6 +126,7 @@ edit
if (i.metadata.selfLink) { delete i.metadata.selfLink } if (i.metadata.selfLink) { delete i.metadata.selfLink }
if (i.metadata.uid) { delete i.metadata.uid } if (i.metadata.uid) { delete i.metadata.uid }
if (i.metadata.resourceVersion) { delete i.metadata.resourceVersion } if (i.metadata.resourceVersion) { delete i.metadata.resourceVersion }
if (i.metadata.managedFields) { delete i.metadata.managedFields }
this.update() this.update()
this.refs.yamlNice.innerHTML = yamlParser.safeDump(i.postgresql, {sortKeys: true}) this.refs.yamlNice.innerHTML = yamlParser.safeDump(i.postgresql, {sortKeys: true})
@ -138,7 +139,15 @@ edit
o.spec.enableMasterLoadBalancer = i.spec.enableMasterLoadBalancer || false o.spec.enableMasterLoadBalancer = i.spec.enableMasterLoadBalancer || false
o.spec.enableReplicaLoadBalancer = i.spec.enableReplicaLoadBalancer || false o.spec.enableReplicaLoadBalancer = i.spec.enableReplicaLoadBalancer || false
o.spec.enableConnectionPooler = i.spec.enableConnectionPooler || false o.spec.enableConnectionPooler = i.spec.enableConnectionPooler || false
o.spec.volume = { size: i.spec.volume.size }
o.spec.volume = {
size: i.spec.volume.size,
throughput: i.spec.volume.throughput || 125,
iops: i.spec.volume.iops || 3000
}
o.spec.postgresql = {}
o.spec.postgresql.version = i.spec.postgresql.version
if ('users' in i.spec && typeof i.spec.users === 'object') { if ('users' in i.spec && typeof i.spec.users === 'object') {
o.spec.users = Object.mapValues(i.spec.users, roleFlags => o.spec.users = Object.mapValues(i.spec.users, roleFlags =>
@ -166,7 +175,7 @@ edit
].forEach(resourceType => { ].forEach(resourceType => {
if (resourceType in resources) { if (resourceType in resources) {
const resourceClaim = resources[resourceType] const resourceClaim = resources[resourceType]
if (typeof resourceClaim === '') { if (typeof resourceClaim === 'string') {
o.spec.resources[section][resourceType] = resources[resourceType] o.spec.resources[section][resourceType] = resources[resourceType]
} }
} }

View File

@ -13,6 +13,6 @@ help-general
h3 Basics h3 Basics
p. p.
The PostgreSQL operator will use your definition to create a new The Postgres Operator will use your definition to create a new
PostgreSQL cluster for you. You can either copy the yaml definition PostgreSQL cluster for you. You can either copy the yaml definition
to the repositiory or you can just hit create cluster. to a repositiory or hit create cluster (not available in prod).

View File

@ -266,6 +266,37 @@ new
) )
.input-group-addon .input-group-addon
.input-units Gi .input-units Gi
tr
td
td Specify Iops and Throughput only if you need more than the default 3000 Iops and 125Mb/s EBS provides.
tr
td Iops
td
.input-group
input.form-control(
ref='iops'
type='number'
value='{ iops }'
onchange='{ iopsChange }'
onkeyup='{ iopsChange }'
)
.input-group-addon
.input-units
tr
td Througput
td
.input-group
input.form-control(
ref='throughput'
type='number'
value='{ throughput }'
onchange='{ throughputChange }'
onkeyup='{ throughputChange }'
)
.input-group-addon
.input-units MB/s
tr(if='{ config.users_visible }') tr(if='{ config.users_visible }')
td td
@ -509,7 +540,9 @@ new
enableConnectionPooler: true enableConnectionPooler: true
{{/if}} {{/if}}
volume: volume:
size: "{{ volumeSize }}Gi" size: "{{ volumeSize }}Gi"{{#if iops}}
iops: {{ iops }}{{/if}}{{#if throughput}}
throughput: {{ throughput }}{{/if}}
{{#if users}} {{#if users}}
users:{{#each users}} users:{{#each users}}
{{ state }}: []{{/each}}{{/if}} {{ state }}: []{{/each}}{{/if}}
@ -560,6 +593,8 @@ new
enableReplicaLoadBalancer: this.enableReplicaLoadBalancer, enableReplicaLoadBalancer: this.enableReplicaLoadBalancer,
enableConnectionPooler: this.enableConnectionPooler, enableConnectionPooler: this.enableConnectionPooler,
volumeSize: this.volumeSize, volumeSize: this.volumeSize,
iops: this.iops,
throughput: this.throughput,
users: this.users.valids, users: this.users.valids,
databases: this.databases.valids, databases: this.databases.valids,
ranges: this.ranges, ranges: this.ranges,
@ -624,6 +659,14 @@ new
this.volumeSize = +e.target.value this.volumeSize = +e.target.value
} }
this.iopsChange = e => {
this.iops = +e.target.value
}
this.throughputChange = e => {
this.throughput = +e.target.value
}
this.updateDNSName = () => { this.updateDNSName = () => {
this.dnsName = this.config.dns_format_string.format( this.dnsName = this.config.dns_format_string.format(
this.name, this.name,

View File

@ -69,7 +69,7 @@ postgresqls
td { cpu } / { cpu_limit } td { cpu } / { cpu_limit }
td { memory } / { memory_limit } td { memory } / { memory_limit }
td { volume_size } td { volume_size }
td { calcCosts(nodes, cpu, memory, volume_size) }$ td { calcCosts(nodes, cpu, memory, volume_size, iops, throughput) }$
td td
@ -152,7 +152,7 @@ postgresqls
td { cpu } / { cpu_limit } td { cpu } / { cpu_limit }
td { memory } / { memory_limit } td { memory } / { memory_limit }
td { volume_size } td { volume_size }
td { calcCosts(nodes, cpu, memory, volume_size) }$ td { calcCosts(nodes, cpu, memory, volume_size, iops, throughput) }$
td td
@ -227,9 +227,22 @@ postgresqls
+ '/' + encodeURI(cluster.name) + '/' + encodeURI(cluster.name)
) )
const calcCosts = this.calcCosts = (nodes, cpu, memory, disk) => { const calcCosts = this.calcCosts = (nodes, cpu, memory, disk, iops, throughput) => {
costs = Math.max(nodes, opts.config.min_pods) * (toCores(cpu) * opts.config.cost_core + toMemory(memory) * opts.config.cost_memory + toDisk(disk) * opts.config.cost_ebs) podcount = Math.max(nodes, opts.config.min_pods)
return costs.toFixed(2) corecost = toCores(cpu) * opts.config.cost_core
memorycost = toMemory(memory) * opts.config.cost_memory
diskcost = toDisk(disk) * opts.config.cost_ebs
iopscost = 0
if (iops !== undefined && iops > 3000) {
iopscost = (iops - 3000) * opts.config.cost_iops
}
throughputcost = 0
if (throughput !== undefined && throughput > 125) {
throughputcost = (throughput - 125) * opts.config.cost_throughput
}
costs = podcount * (corecost + memorycost + diskcost + iopscost + throughputcost)
return costs.toFixed(2)
} }
const toDisk = this.toDisk = value => { const toDisk = this.toDisk = value => {
@ -253,6 +266,11 @@ postgresqls
value = Number(value) value = Number(value)
return value return value
} }
else if(value.endsWith("Ti")) {
value = value.substring(0, value.length-2)
value = Number(value) * 1000
return value
}
return value return value
} }

View File

@ -62,7 +62,9 @@ spec:
"replica_load_balancer_visible": true, "replica_load_balancer_visible": true,
"resources_visible": true, "resources_visible": true,
"users_visible": true, "users_visible": true,
"cost_ebs": 0.119, "cost_ebs": 0.0952,
"cost_iops": 0.006,
"cost_throughput": 0.0476,
"cost_core": 0.0575, "cost_core": 0.0575,
"cost_memory": 0.014375, "cost_memory": 0.014375,
"postgresql_versions": [ "postgresql_versions": [

View File

@ -89,8 +89,10 @@ TARGET_NAMESPACE = getenv('TARGET_NAMESPACE')
GOOGLE_ANALYTICS = getenv('GOOGLE_ANALYTICS', False) GOOGLE_ANALYTICS = getenv('GOOGLE_ANALYTICS', False)
MIN_PODS= getenv('MIN_PODS', 2) MIN_PODS= getenv('MIN_PODS', 2)
# storage pricing, i.e. https://aws.amazon.com/ebs/pricing/ # storage pricing, i.e. https://aws.amazon.com/ebs/pricing/ (e.g. Europe - Franfurt)
COST_EBS = float(getenv('COST_EBS', 0.119)) # GB per month COST_EBS = float(getenv('COST_EBS', 0.0952)) # GB per month
COST_IOPS = float(getenv('COST_IOPS', 0.006)) # IOPS per month above 3000 baseline
COST_THROUGHPUT = float(getenv('COST_THROUGHPUT', 0.0476)) # MB/s per month above 125 MB/s baseline
# compute costs, i.e. https://www.ec2instances.info/?region=eu-central-1&selected=m5.2xlarge # compute costs, i.e. https://www.ec2instances.info/?region=eu-central-1&selected=m5.2xlarge
COST_CORE = 30.5 * 24 * float(getenv('COST_CORE', 0.0575)) # Core per hour m5.2xlarge / 8. COST_CORE = 30.5 * 24 * float(getenv('COST_CORE', 0.0575)) # Core per hour m5.2xlarge / 8.
@ -308,6 +310,8 @@ DEFAULT_UI_CONFIG = {
'pgui_link': '', 'pgui_link': '',
'static_network_whitelist': {}, 'static_network_whitelist': {},
'cost_ebs': COST_EBS, 'cost_ebs': COST_EBS,
'cost_iops': COST_IOPS,
'cost_throughput': COST_THROUGHPUT,
'cost_core': COST_CORE, 'cost_core': COST_CORE,
'cost_memory': COST_MEMORY, 'cost_memory': COST_MEMORY,
'min_pods': MIN_PODS 'min_pods': MIN_PODS
@ -487,6 +491,8 @@ def get_postgresqls():
'cpu': spec.get('resources', {}).get('requests', {}).get('cpu', 0), 'cpu': spec.get('resources', {}).get('requests', {}).get('cpu', 0),
'cpu_limit': spec.get('resources', {}).get('limits', {}).get('cpu', 0), 'cpu_limit': spec.get('resources', {}).get('limits', {}).get('cpu', 0),
'volume_size': spec.get('volume', {}).get('size', 0), 'volume_size': spec.get('volume', {}).get('size', 0),
'iops': spec.get('volume', {}).get('iops', 3000),
'throughput': spec.get('volume', {}).get('throughput', 125),
'team': ( 'team': (
spec.get('teamId') or spec.get('teamId') or
metadata.get('labels', {}).get('team', '') metadata.get('labels', {}).get('team', '')
@ -614,6 +620,28 @@ def update_postgresql(namespace: str, cluster: str):
spec['volume'] = {'size': size} spec['volume'] = {'size': size}
if (
'volume' in postgresql['spec']
and 'iops' in postgresql['spec']['volume']
and postgresql['spec']['volume']['iops'] != None
):
iops = int(postgresql['spec']['volume']['iops'])
if not 'volume' in spec:
spec['volume'] = {}
spec['volume']['iops'] = iops
if (
'volume' in postgresql['spec']
and 'throughput' in postgresql['spec']['volume']
and postgresql['spec']['volume']['throughput'] != None
):
throughput = int(postgresql['spec']['volume']['throughput'])
if not 'volume' in spec:
spec['volume'] = {}
spec['volume']['throughput'] = throughput
if 'enableConnectionPooler' in postgresql['spec']: if 'enableConnectionPooler' in postgresql['spec']:
cp = postgresql['spec']['enableConnectionPooler'] cp = postgresql['spec']['enableConnectionPooler']
if not cp: if not cp:
@ -758,6 +786,27 @@ def update_postgresql(namespace: str, cluster: str):
owner_username=owner_username, owner_username=owner_username,
) )
resource_types = ["cpu","memory"]
resource_constraints = ["requests","limits"]
if "resources" in postgresql["spec"]:
spec["resources"] = {}
res = postgresql["spec"]["resources"]
for rt in resource_types:
for rc in resource_constraints:
if rc in res:
if rt in res[rc]:
if not rc in spec["resources"]:
spec["resources"][rc] = {}
spec["resources"][rc][rt] = res[rc][rt]
if "postgresql" in postgresql["spec"]:
if "version" in postgresql["spec"]["postgresql"]:
if "postgresql" not in spec:
spec["postgresql"]={}
spec["postgresql"]["version"] = postgresql["spec"]["postgresql"]["version"]
o['spec'].update(spec) o['spec'].update(spec)
apply_postgresql(get_cluster(), namespace, cluster, o) apply_postgresql(get_cluster(), namespace, cluster, o)

View File

@ -19,7 +19,9 @@ default_operator_ui_config='{
"nat_gateways_visible": false, "nat_gateways_visible": false,
"resources_visible": true, "resources_visible": true,
"users_visible": true, "users_visible": true,
"cost_ebs": 0.119, "cost_ebs": 0.0952,
"cost_iops": 0.006,
"cost_throughput": 0.0476,
"cost_core": 0.0575, "cost_core": 0.0575,
"cost_memory": 0.014375, "cost_memory": 0.014375,
"postgresql_versions": [ "postgresql_versions": [