Skip to content

Commit ccb52c0

Browse files
authored
[UI] Remove deprecated WAL-E library and enable WAL-G backup support in UI backend (#2915)
1 parent 68c4b49 commit ccb52c0

File tree

5 files changed

+58
-46
lines changed

5 files changed

+58
-46
lines changed

charts/postgres-operator-ui/values.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,6 @@ podAnnotations:
6262
extraEnvs:
6363
[]
6464
# Exemple of settings to make snapshot view working in the ui when using AWS
65-
# - name: WALE_S3_ENDPOINT
66-
# value: https+path://s3.us-east-1.amazonaws.com:443
6765
# - name: SPILO_S3_BACKUP_PREFIX
6866
# value: spilo/
6967
# - name: AWS_ACCESS_KEY_ID
@@ -83,8 +81,6 @@ extraEnvs:
8381
# key: AWS_DEFAULT_REGION
8482
# - name: SPILO_S3_BACKUP_BUCKET
8583
# value: <s3 bucket used by the operator>
86-
# - name: "USE_AWS_INSTANCE_PROFILE"
87-
# value: "true"
8884

8985
# configure UI service
9086
service:

ui/manifests/deployment.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,6 @@ spec:
8181
]
8282
}
8383
# Exemple of settings to make snapshot view working in the ui when using AWS
84-
# - name: WALE_S3_ENDPOINT
85-
# value: https+path://s3.us-east-1.amazonaws.com:443
8684
# - name: SPILO_S3_BACKUP_PREFIX
8785
# value: spilo/
8886
# - name: AWS_ACCESS_KEY_ID
@@ -102,5 +100,3 @@ spec:
102100
# key: AWS_DEFAULT_REGION
103101
# - name: SPILO_S3_BACKUP_BUCKET
104102
# value: <s3 bucket used by the operator>
105-
# - name: "USE_AWS_INSTANCE_PROFILE"
106-
# value: "true"

ui/operator_ui/main.py

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,6 @@
9595
DEFAULT_CPU = getenv('DEFAULT_CPU', '10m')
9696
DEFAULT_CPU_LIMIT = getenv('DEFAULT_CPU_LIMIT', '300m')
9797

98-
WALE_S3_ENDPOINT = getenv(
99-
'WALE_S3_ENDPOINT',
100-
'https+path://s3.eu-central-1.amazonaws.com:443',
101-
)
102-
103-
USE_AWS_INSTANCE_PROFILE = (
104-
getenv('USE_AWS_INSTANCE_PROFILE', 'false').lower() != 'false'
105-
)
10698

10799
AWS_ENDPOINT = getenv('AWS_ENDPOINT')
108100

@@ -784,8 +776,6 @@ def get_versions(pg_cluster: str):
784776
bucket=SPILO_S3_BACKUP_BUCKET,
785777
pg_cluster=pg_cluster,
786778
prefix=SPILO_S3_BACKUP_PREFIX,
787-
s3_endpoint=WALE_S3_ENDPOINT,
788-
use_aws_instance_profile=USE_AWS_INSTANCE_PROFILE,
789779
),
790780
)
791781

@@ -797,9 +787,8 @@ def get_basebackups(pg_cluster: str, uid: str):
797787
bucket=SPILO_S3_BACKUP_BUCKET,
798788
pg_cluster=pg_cluster,
799789
prefix=SPILO_S3_BACKUP_PREFIX,
800-
s3_endpoint=WALE_S3_ENDPOINT,
801790
uid=uid,
802-
use_aws_instance_profile=USE_AWS_INSTANCE_PROFILE,
791+
postgresql_versions=OPERATOR_UI_CONFIG.get('postgresql_versions', DEFAULT_UI_CONFIG['postgresql_versions']),
803792
),
804793
)
805794

@@ -991,8 +980,6 @@ def main(port, debug, clusters: list):
991980
logger.info(f'Superuser team: {SUPERUSER_TEAM}')
992981
logger.info(f'Target namespace: {TARGET_NAMESPACE}')
993982
logger.info(f'Teamservice URL: {TEAM_SERVICE_URL}')
994-
logger.info(f'Use AWS instance_profile: {USE_AWS_INSTANCE_PROFILE}')
995-
logger.info(f'WAL-E S3 endpoint: {WALE_S3_ENDPOINT}')
996983
logger.info(f'AWS S3 endpoint: {AWS_ENDPOINT}')
997984

998985
if TARGET_NAMESPACE is None:

ui/operator_ui/spiloutils.py

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@
66
from requests import Session
77
from urllib.parse import urljoin
88
from uuid import UUID
9-
from wal_e.cmd import configure_backup_cxt
109

11-
from .utils import Attrs, defaulting, these
10+
from .utils import defaulting, these
1211
from operator_ui.adapters.logger import logger
1312

1413
session = Session()
@@ -284,10 +283,8 @@ def read_stored_clusters(bucket, prefix, delimiter='/'):
284283
def read_versions(
285284
pg_cluster,
286285
bucket,
287-
s3_endpoint,
288286
prefix,
289287
delimiter='/',
290-
use_aws_instance_profile=False,
291288
):
292289
return [
293290
'base' if uid == 'wal' else uid
@@ -305,35 +302,72 @@ def read_versions(
305302
if uid == 'wal' or defaulting(lambda: UUID(uid))
306303
]
307304

308-
BACKUP_VERSION_PREFIXES = ['', '10/', '11/', '12/', '13/', '14/', '15/', '16/', '17/']
305+
def lsn_to_wal_segment_stop(finish_lsn, start_segment, wal_segment_size=16 * 1024 * 1024):
306+
timeline = int(start_segment[:8], 16)
307+
log_id = finish_lsn >> 32
308+
seg_id = (finish_lsn & 0xFFFFFFFF) // wal_segment_size
309+
return f"{timeline:08X}{log_id:08X}{seg_id:08X}"
310+
311+
def lsn_to_offset_hex(lsn, wal_segment_size=16 * 1024 * 1024):
312+
return f"{lsn % wal_segment_size:08X}"
309313

310314
def read_basebackups(
311315
pg_cluster,
312316
uid,
313317
bucket,
314-
s3_endpoint,
315318
prefix,
316-
delimiter='/',
317-
use_aws_instance_profile=False,
319+
postgresql_versions,
318320
):
319-
environ['WALE_S3_ENDPOINT'] = s3_endpoint
320321
suffix = '' if uid == 'base' else '/' + uid
321322
backups = []
322323

323-
for vp in BACKUP_VERSION_PREFIXES:
324-
325-
backups = backups + [
326-
{
327-
key: value
328-
for key, value in basebackup.__dict__.items()
329-
if isinstance(value, str) or isinstance(value, int)
330-
}
331-
for basebackup in Attrs.call(
332-
f=configure_backup_cxt,
333-
aws_instance_profile=use_aws_instance_profile,
334-
s3_prefix=f's3://{bucket}/{prefix}{pg_cluster}{suffix}/wal/{vp}',
335-
)._backup_list(detail=True)
336-
]
324+
for vp in postgresql_versions:
325+
backup_prefix = f'{prefix}{pg_cluster}{suffix}/wal/{vp}/basebackups_005/'
326+
logger.info(f"{bucket}/{backup_prefix}")
327+
328+
paginator = client('s3').get_paginator('list_objects_v2')
329+
pages = paginator.paginate(Bucket=bucket, Prefix=backup_prefix)
330+
331+
for page in pages:
332+
for obj in page.get("Contents", []):
333+
key = obj["Key"]
334+
if not key.endswith("backup_stop_sentinel.json"):
335+
continue
336+
337+
response = client('s3').get_object(Bucket=bucket, Key=key)
338+
backup_info = loads(response["Body"].read().decode("utf-8"))
339+
last_modified = response["LastModified"].astimezone(timezone.utc).isoformat()
340+
341+
backup_name = key.split("/")[-1].replace("_backup_stop_sentinel.json", "")
342+
start_seg, start_offset = backup_name.split("_")[1], backup_name.split("_")[-1] if "_" in backup_name else None
343+
344+
if "LSN" in backup_info and "FinishLSN" in backup_info:
345+
# WAL-G
346+
lsn = backup_info["LSN"]
347+
finish_lsn = backup_info["FinishLSN"]
348+
backups.append({
349+
"expanded_size_bytes": backup_info.get("UncompressedSize"),
350+
"last_modified": last_modified,
351+
"name": backup_name,
352+
"wal_segment_backup_start": start_seg,
353+
"wal_segment_backup_stop": lsn_to_wal_segment_stop(finish_lsn, start_seg),
354+
"wal_segment_offset_backup_start": lsn_to_offset_hex(lsn),
355+
"wal_segment_offset_backup_stop": lsn_to_offset_hex(finish_lsn),
356+
})
357+
elif "wal_segment_backup_stop" in backup_info:
358+
# WAL-E
359+
stop_seg = backup_info["wal_segment_backup_stop"]
360+
stop_offset = backup_info["wal_segment_offset_backup_stop"]
361+
362+
backups.append({
363+
"expanded_size_bytes": backup_info.get("expanded_size_bytes"),
364+
"last_modified": last_modified,
365+
"name": backup_name,
366+
"wal_segment_backup_start": start_seg,
367+
"wal_segment_backup_stop": stop_seg,
368+
"wal_segment_offset_backup_start": start_offset,
369+
"wal_segment_offset_backup_stop": stop_offset,
370+
})
337371

338372
return backups
339373

ui/requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,4 @@ kubernetes==11.0.0
1111
python-json-logger==2.0.7
1212
requests==2.32.2
1313
stups-tokens>=1.1.19
14-
wal_e==1.1.1
1514
werkzeug==3.0.6

0 commit comments

Comments
 (0)