From 8d71953246fdc920a3608059205f59149f1e3b4a Mon Sep 17 00:00:00 2001 From: Felix Kunde Date: Thu, 24 Mar 2022 19:10:18 +0100 Subject: [PATCH] [UI] support Postgres version and pod resource changes + adding IOPS and throughput config options --- ui/app/src/edit.tag.pug | 13 ++++++-- ui/app/src/help-general.tag.pug | 4 +-- ui/app/src/new.tag.pug | 45 +++++++++++++++++++++++++++- ui/app/src/postgresqls.tag.pug | 28 +++++++++++++---- ui/manifests/deployment.yaml | 4 ++- ui/operator_ui/main.py | 53 +++++++++++++++++++++++++++++++-- ui/run_local.sh | 4 ++- 7 files changed, 137 insertions(+), 14 deletions(-) diff --git a/ui/app/src/edit.tag.pug b/ui/app/src/edit.tag.pug index c1d94e589..bb536a8e4 100644 --- a/ui/app/src/edit.tag.pug +++ b/ui/app/src/edit.tag.pug @@ -126,6 +126,7 @@ edit if (i.metadata.selfLink) { delete i.metadata.selfLink } if (i.metadata.uid) { delete i.metadata.uid } if (i.metadata.resourceVersion) { delete i.metadata.resourceVersion } + if (i.metadata.managedFields) { delete i.metadata.managedFields } this.update() this.refs.yamlNice.innerHTML = yamlParser.safeDump(i.postgresql, {sortKeys: true}) @@ -138,7 +139,15 @@ edit 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 } + + 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') { o.spec.users = Object.mapValues(i.spec.users, roleFlags => @@ -166,7 +175,7 @@ edit ].forEach(resourceType => { if (resourceType in resources) { const resourceClaim = resources[resourceType] - if (typeof resourceClaim === '') { + if (typeof resourceClaim === 'string') { o.spec.resources[section][resourceType] = resources[resourceType] } } diff --git a/ui/app/src/help-general.tag.pug b/ui/app/src/help-general.tag.pug index 1af25f1a8..7771fcebd 100644 --- a/ui/app/src/help-general.tag.pug +++ b/ui/app/src/help-general.tag.pug @@ -13,6 +13,6 @@ help-general h3 Basics 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 - to the repositiory or you can just hit create cluster. + to a repositiory or hit create cluster (not available in prod). diff --git a/ui/app/src/new.tag.pug b/ui/app/src/new.tag.pug index 6293a6c7a..a2b0506da 100644 --- a/ui/app/src/new.tag.pug +++ b/ui/app/src/new.tag.pug @@ -266,6 +266,37 @@ new ) .input-group-addon .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 }') td @@ -509,7 +540,9 @@ new enableConnectionPooler: true {{/if}} volume: - size: "{{ volumeSize }}Gi" + size: "{{ volumeSize }}Gi"{{#if iops}} + iops: {{ iops }}{{/if}}{{#if throughput}} + throughput: {{ throughput }}{{/if}} {{#if users}} users:{{#each users}} {{ state }}: []{{/each}}{{/if}} @@ -560,6 +593,8 @@ new enableReplicaLoadBalancer: this.enableReplicaLoadBalancer, enableConnectionPooler: this.enableConnectionPooler, volumeSize: this.volumeSize, + iops: this.iops, + throughput: this.throughput, users: this.users.valids, databases: this.databases.valids, ranges: this.ranges, @@ -624,6 +659,14 @@ new this.volumeSize = +e.target.value } + this.iopsChange = e => { + this.iops = +e.target.value + } + + this.throughputChange = e => { + this.throughput = +e.target.value + } + this.updateDNSName = () => { this.dnsName = this.config.dns_format_string.format( this.name, diff --git a/ui/app/src/postgresqls.tag.pug b/ui/app/src/postgresqls.tag.pug index 38e5fcd9d..fabf769a0 100644 --- a/ui/app/src/postgresqls.tag.pug +++ b/ui/app/src/postgresqls.tag.pug @@ -69,7 +69,7 @@ postgresqls td { cpu } / { cpu_limit } td { memory } / { memory_limit } td { volume_size } - td { calcCosts(nodes, cpu, memory, volume_size) }$ + td { calcCosts(nodes, cpu, memory, volume_size, iops, throughput) }$ td @@ -152,7 +152,7 @@ postgresqls td { cpu } / { cpu_limit } td { memory } / { memory_limit } td { volume_size } - td { calcCosts(nodes, cpu, memory, volume_size) }$ + td { calcCosts(nodes, cpu, memory, volume_size, iops, throughput) }$ td @@ -227,9 +227,22 @@ postgresqls + '/' + encodeURI(cluster.name) ) - const calcCosts = this.calcCosts = (nodes, cpu, memory, disk) => { - 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) - return costs.toFixed(2) + const calcCosts = this.calcCosts = (nodes, cpu, memory, disk, iops, throughput) => { + podcount = Math.max(nodes, opts.config.min_pods) + 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 => { @@ -253,6 +266,11 @@ postgresqls value = Number(value) return value } + else if(value.endsWith("Ti")) { + value = value.substring(0, value.length-2) + value = Number(value) * 1000 + return value + } return value } diff --git a/ui/manifests/deployment.yaml b/ui/manifests/deployment.yaml index 865acd6b9..b2af47790 100644 --- a/ui/manifests/deployment.yaml +++ b/ui/manifests/deployment.yaml @@ -62,7 +62,9 @@ spec: "replica_load_balancer_visible": true, "resources_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_memory": 0.014375, "postgresql_versions": [ diff --git a/ui/operator_ui/main.py b/ui/operator_ui/main.py index dc207d35e..3e1e54969 100644 --- a/ui/operator_ui/main.py +++ b/ui/operator_ui/main.py @@ -89,8 +89,10 @@ GOOGLE_ANALYTICS = getenv('GOOGLE_ANALYTICS', False) MIN_PODS= getenv('MIN_PODS', 2) -# storage pricing, i.e. https://aws.amazon.com/ebs/pricing/ -COST_EBS = float(getenv('COST_EBS', 0.119)) # GB per month +# storage pricing, i.e. https://aws.amazon.com/ebs/pricing/ (e.g. Europe - Franfurt) +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 COST_CORE = 30.5 * 24 * float(getenv('COST_CORE', 0.0575)) # Core per hour m5.2xlarge / 8. @@ -308,6 +310,8 @@ def index(): 'pgui_link': '', 'static_network_whitelist': {}, 'cost_ebs': COST_EBS, + 'cost_iops': COST_IOPS, + 'cost_throughput': COST_THROUGHPUT, 'cost_core': COST_CORE, 'cost_memory': COST_MEMORY, 'min_pods': MIN_PODS @@ -487,6 +491,8 @@ def get_postgresqls(): 'cpu': spec.get('resources', {}).get('requests', {}).get('cpu', 0), 'cpu_limit': spec.get('resources', {}).get('limits', {}).get('cpu', 0), 'volume_size': spec.get('volume', {}).get('size', 0), + 'iops': spec.get('volume', {}).get('iops', 3000), + 'throughput': spec.get('volume', {}).get('throughput', 125), 'team': ( spec.get('teamId') or metadata.get('labels', {}).get('team', '') @@ -614,6 +620,28 @@ def update_postgresql(namespace: str, cluster: str): 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']: cp = postgresql['spec']['enableConnectionPooler'] if not cp: @@ -758,6 +786,27 @@ def update_postgresql(namespace: str, cluster: str): 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) apply_postgresql(get_cluster(), namespace, cluster, o) diff --git a/ui/run_local.sh b/ui/run_local.sh index 33c0abf27..e23b43423 100755 --- a/ui/run_local.sh +++ b/ui/run_local.sh @@ -19,7 +19,9 @@ default_operator_ui_config='{ "nat_gateways_visible": false, "resources_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_memory": 0.014375, "postgresql_versions": [