Skip to content

Commit 3d3edaf

Browse files
committed
STAC-23457 Load stackpack backups from S3proxy
1 parent 3f3c4b8 commit 3d3edaf

12 files changed

Lines changed: 141 additions & 72 deletions

File tree

cmd/elasticsearch/list_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ stackgraph:
6868
restore:
6969
scaleDownLabelSelector: "app=stackgraph"
7070
loggingConfigConfigMap: logging-config
71+
stsBackupConfigConfigMap: backup-config
7172
zookeeperQuorum: "zookeeper:2181"
7273
job:
7374
image: backup:latest
@@ -107,6 +108,7 @@ settings:
107108
restore:
108109
scaleDownLabelSelector: "app=settings"
109110
loggingConfigConfigMap: logging-config
111+
stsBackupConfigConfigMap: backup-config
110112
baseUrl: "http://server:7070"
111113
receiverBaseUrl: "http://receiver:7077"
112114
platformVersion: "5.2.0"
@@ -152,6 +154,7 @@ stackgraph:
152154
restore:
153155
scaleDownLabelSelector: "app=stackgraph"
154156
loggingConfigConfigMap: logging-config
157+
stsBackupConfigConfigMap: backup-config
155158
zookeeperQuorum: "zookeeper:2181"
156159
job:
157160
image: backup:latest
@@ -192,6 +195,7 @@ settings:
192195
restore:
193196
scaleDownLabelSelector: "app=settings"
194197
loggingConfigConfigMap: logging-config
198+
stsBackupConfigConfigMap: backup-config
195199
baseUrl: "http://server:7070"
196200
receiverBaseUrl: "http://receiver:7077"
197201
platformVersion: "5.2.0"

cmd/settings/list.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ func getBackupListFromLocalBucket(appCtx *app.Context) ([]BackupFileInfo, error)
238238
return nil, fmt.Errorf("failed to list objects in local bucket: %w", err)
239239
}
240240

241-
filteredObjects := s3client.FilterBackupObjects(result.Contents, isMultiPartArchive)
241+
filteredObjects := s3client.FilterMultipartBackupObjects(result.Contents, isMultiPartArchive)
242242

243243
filteredObjects, err = s3client.FilterByPrefixAndRegex(filteredObjects, "", backupFileNameRegex)
244244
if err != nil {

cmd/settings/restore.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,9 @@ func buildEnvVar(extraEnvVar []corev1.EnvVar, config *config.Config) []corev1.En
196196
{Name: "BACKUP_CONFIGURATION_S3_PREFIX", Value: config.Settings.S3Prefix},
197197
{Name: "BACKUP_CONFIGURATION_STACKPACKS_S3_PREFIX", Value: config.Settings.StackpacksS3Prefix},
198198
{Name: "MINIO_ENDPOINT", Value: fmt.Sprintf("%s:%d", storageService.Name, storageService.Port)},
199-
{Name: "STACKSTATE_BASE_URL", Value: config.Settings.Restore.BaseURL},
200-
{Name: "RECEIVER_BASE_URL", Value: config.Settings.Restore.ReceiverBaseURL},
201-
{Name: "PLATFORM_VERSION", Value: config.Settings.Restore.PlatformVersion},
199+
{Name: "STACKSTATE_BASE_URL", Value: config.GetBaseURL()},
200+
{Name: "RECEIVER_BASE_URL", Value: config.GetReceiverBaseURL()},
201+
{Name: "PLATFORM_VERSION", Value: config.GetPlatformVersion()},
202202
{Name: "ZOOKEEPER_QUORUM", Value: config.Settings.Restore.ZookeeperQuorum},
203203
{Name: "BACKUP_CONFIGURATION_UPLOAD_REMOTE", Value: strconv.FormatBool(config.GlobalBackupEnabled())},
204204
{Name: "SKIP_STACKPACKS", Value: strconv.FormatBool(skipStackpacks)},

cmd/stackgraph/restore.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"fmt"
66
"sort"
77
"strconv"
8-
"strings"
98
"time"
109

1110
"github.com/aws/aws-sdk-go-v2/aws"
@@ -182,6 +181,13 @@ func getLatestBackup(k8sClient *k8s.Client, namespace string, config *config.Con
182181
// Filter objects based on whether the archive is split or not
183182
filteredObjects := s3client.FilterMultipartBackupObjects(result.Contents, multipartArchive)
184183

184+
// Filter to only include direct children of the prefix that match the backup filename pattern,
185+
// and strip the prefix from the key
186+
filteredObjects, err = s3client.FilterByPrefixAndRegex(filteredObjects, prefix, backupFileNameRegex)
187+
if err != nil {
188+
return "", fmt.Errorf("failed to filter objects: %w", err)
189+
}
190+
185191
if len(filteredObjects) == 0 {
186192
return "", fmt.Errorf("no backups found in bucket %s", bucket)
187193
}
@@ -190,8 +196,7 @@ func getLatestBackup(k8sClient *k8s.Client, namespace string, config *config.Con
190196
sort.Slice(filteredObjects, func(i, j int) bool {
191197
return filteredObjects[i].LastModified.After(filteredObjects[j].LastModified)
192198
})
193-
latestBackup := strings.TrimPrefix(filteredObjects[0].Key, prefix)
194-
return latestBackup, nil
199+
return filteredObjects[0].Key, nil
195200
}
196201

197202
// buildPVCSpec builds a PVCSpec from configuration
@@ -273,6 +278,9 @@ func buildRestoreEnvVars(backupFile string, config *config.Config) []corev1.EnvV
273278
{Name: "BACKUP_STACKGRAPH_STACKPACKS_S3_PREFIX", Value: config.Stackgraph.StackpacksS3Prefix},
274279
{Name: "BACKUP_STACKGRAPH_MULTIPART_ARCHIVE", Value: strconv.FormatBool(config.Stackgraph.MultipartArchive)},
275280
{Name: "MINIO_ENDPOINT", Value: fmt.Sprintf("%s:%d", storageService.Name, storageService.Port)},
281+
{Name: "STACKSTATE_BASE_URL", Value: config.GetBaseURL()},
282+
{Name: "RECEIVER_BASE_URL", Value: config.GetReceiverBaseURL()},
283+
{Name: "PLATFORM_VERSION", Value: config.GetPlatformVersion()},
276284
{Name: "ZOOKEEPER_QUORUM", Value: config.Stackgraph.Restore.ZookeeperQuorum},
277285
{Name: "SKIP_STACKPACKS", Value: strconv.FormatBool(skipStackpacks)},
278286
}

internal/clients/s3/filter_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ func TestFilterBackupObjects_SizeSummation(t *testing.T) {
366366
}
367367

368368
// TestFilterByPrefixAndRegex tests the combined filtering by prefix and regex pattern
369-
func TestFilterByPrefixAndRegex(t *testing.T) {
369+
func TestFilterByPrefixAndRegex(t *testing.T) { //nolint:funlen // Table-driven test
370370
now := time.Now()
371371

372372
tests := []struct {

internal/foundation/config/config.go

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,49 @@ type Config struct {
2020
Elasticsearch ElasticsearchConfig `yaml:"elasticsearch" validate:"required"`
2121
Minio MinioConfig `yaml:"minio"`
2222
Storage StorageConfig `yaml:"storage"`
23+
Stackstate StackstateConfig `yaml:"stackstate"`
2324
Stackgraph StackgraphConfig `yaml:"stackgraph" validate:"required"`
2425
Settings SettingsConfig `yaml:"settings" validate:"required"`
2526
VictoriaMetrics VictoriaMetricsConfig `yaml:"victoriaMetrics" validate:"required"`
2627
Clickhouse ClickhouseConfig `yaml:"clickhouse" validate:"required"`
2728
}
2829

30+
// StackstateConfig holds platform-wide configuration shared across restore operations.
31+
// These values are used by both Settings and Stackgraph restore jobs.
32+
// When set, they take precedence over the per-restore-type fields in SettingsRestoreConfig.
33+
type StackstateConfig struct {
34+
BaseURL string `yaml:"baseUrl"`
35+
ReceiverBaseURL string `yaml:"receiverBaseUrl"`
36+
PlatformVersion string `yaml:"platformVersion"`
37+
}
38+
39+
// GetBaseURL returns the StackState base URL, preferring the top-level stackstate section
40+
// over the legacy settings.restore.baseUrl for backward compatibility.
41+
func (c *Config) GetBaseURL() string {
42+
if c.Stackstate.BaseURL != "" {
43+
return c.Stackstate.BaseURL
44+
}
45+
return c.Settings.Restore.BaseURL
46+
}
47+
48+
// GetReceiverBaseURL returns the receiver base URL, preferring the top-level stackstate section
49+
// over the legacy settings.restore.receiverBaseUrl for backward compatibility.
50+
func (c *Config) GetReceiverBaseURL() string {
51+
if c.Stackstate.ReceiverBaseURL != "" {
52+
return c.Stackstate.ReceiverBaseURL
53+
}
54+
return c.Settings.Restore.ReceiverBaseURL
55+
}
56+
57+
// GetPlatformVersion returns the platform version, preferring the top-level stackstate section
58+
// over the legacy settings.restore.platformVersion for backward compatibility.
59+
func (c *Config) GetPlatformVersion() string {
60+
if c.Stackstate.PlatformVersion != "" {
61+
return c.Stackstate.PlatformVersion
62+
}
63+
return c.Settings.Restore.PlatformVersion
64+
}
65+
2966
// IsLegacyMode returns true when the configuration uses the legacy Minio config.
3067
// Legacy mode is detected by the presence of the Minio config with a non-empty service name.
3168
func (c *Config) IsLegacyMode() bool {
@@ -183,9 +220,9 @@ type SettingsRestoreConfig struct {
183220
ScaleDownLabelSelector string `yaml:"scaleDownLabelSelector" validate:"required"`
184221
LoggingConfigConfigMapName string `yaml:"loggingConfigConfigMap" validate:"required"`
185222
StsBackupConfigConfigMapName string `yaml:"stsBackupConfigConfigMap" validate:"required"`
186-
BaseURL string `yaml:"baseUrl" validate:"required"`
187-
ReceiverBaseURL string `yaml:"receiverBaseUrl" validate:"required"`
188-
PlatformVersion string `yaml:"platformVersion" validate:"required"`
223+
BaseURL string `yaml:"baseUrl"`
224+
ReceiverBaseURL string `yaml:"receiverBaseUrl"`
225+
PlatformVersion string `yaml:"platformVersion"`
189226
ZookeeperQuorum string `yaml:"zookeeperQuorum" validate:"required"`
190227
Job JobConfig `yaml:"job" validate:"required"`
191228
PVC string `yaml:"pvc"` // Required only in legacy mode
@@ -394,6 +431,10 @@ func LoadConfig(clientset kubernetes.Interface, namespace, configMapName, secret
394431
}
395432

396433
// Custom validation: either minio or storage must be configured
434+
if config.GetBaseURL() == "" || config.GetReceiverBaseURL() == "" || config.GetPlatformVersion() == "" {
435+
return nil, fmt.Errorf("configuration validation failed: baseUrl, receiverBaseUrl, and platformVersion must be set in either 'stackstate' or 'settings.restore'")
436+
}
437+
397438
if config.Minio.Service.Name == "" && config.Storage.Service.Name == "" {
398439
return nil, fmt.Errorf("configuration validation failed: either 'minio' or 'storage' must be configured")
399440
}

internal/foundation/config/config_test.go

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -625,9 +625,10 @@ func TestConfig_StructValidation(t *testing.T) {
625625
S3Prefix: "",
626626
MultipartArchive: true,
627627
Restore: StackgraphRestoreConfig{
628-
ScaleDownLabelSelector: "app=stackgraph",
629-
LoggingConfigConfigMapName: "logging-config",
630-
ZookeeperQuorum: "zookeeper:2181",
628+
ScaleDownLabelSelector: "app=stackgraph",
629+
LoggingConfigConfigMapName: "logging-config",
630+
StsBackupConfigConfigMapName: "backup-config",
631+
ZookeeperQuorum: "zookeeper:2181",
631632
Job: JobConfig{
632633
Image: "backup:latest",
633634
WaitImage: "wait:latest",
@@ -682,13 +683,14 @@ func TestConfig_StructValidation(t *testing.T) {
682683
Bucket: "settings-backup",
683684
S3Prefix: "",
684685
Restore: SettingsRestoreConfig{
685-
ScaleDownLabelSelector: "app=settings",
686-
LoggingConfigConfigMapName: "logging-config",
687-
BaseURL: "http://server:7070",
688-
ReceiverBaseURL: "http://receiver:7077",
689-
PlatformVersion: "5.2.0",
690-
ZookeeperQuorum: "zookeeper:2181",
691-
PVC: "suse-observability-settings-backup-data",
686+
ScaleDownLabelSelector: "app=settings",
687+
LoggingConfigConfigMapName: "logging-config",
688+
StsBackupConfigConfigMapName: "backup-config",
689+
BaseURL: "http://server:7070",
690+
ReceiverBaseURL: "http://receiver:7077",
691+
PlatformVersion: "5.2.0",
692+
ZookeeperQuorum: "zookeeper:2181",
693+
PVC: "suse-observability-settings-backup-data",
692694
Job: JobConfig{
693695
Image: "settings-backup:latest",
694696
WaitImage: "wait:latest",
@@ -772,9 +774,10 @@ func TestConfig_StructValidation(t *testing.T) {
772774
S3Prefix: "",
773775
MultipartArchive: true,
774776
Restore: StackgraphRestoreConfig{
775-
ScaleDownLabelSelector: "app=stackgraph",
776-
LoggingConfigConfigMapName: "logging-config",
777-
ZookeeperQuorum: "zookeeper:2181",
777+
ScaleDownLabelSelector: "app=stackgraph",
778+
LoggingConfigConfigMapName: "logging-config",
779+
StsBackupConfigConfigMapName: "backup-config",
780+
ZookeeperQuorum: "zookeeper:2181",
778781
Job: JobConfig{
779782
Image: "backup:latest",
780783
WaitImage: "wait:latest",
@@ -829,12 +832,13 @@ func TestConfig_StructValidation(t *testing.T) {
829832
Bucket: "settings-backup",
830833
S3Prefix: "",
831834
Restore: SettingsRestoreConfig{
832-
ScaleDownLabelSelector: "app=settings",
833-
LoggingConfigConfigMapName: "logging-config",
834-
BaseURL: "http://server:7070",
835-
ReceiverBaseURL: "http://receiver:7077",
836-
PlatformVersion: "5.2.0",
837-
ZookeeperQuorum: "zookeeper:2181",
835+
ScaleDownLabelSelector: "app=settings",
836+
LoggingConfigConfigMapName: "logging-config",
837+
StsBackupConfigConfigMapName: "backup-config",
838+
BaseURL: "http://server:7070",
839+
ReceiverBaseURL: "http://receiver:7077",
840+
PlatformVersion: "5.2.0",
841+
ZookeeperQuorum: "zookeeper:2181",
838842
Job: JobConfig{
839843
Image: "settings-backup:latest",
840844
WaitImage: "wait:latest",

internal/foundation/config/testdata/validConfigMapConfig.yaml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ elasticsearch:
5959
# Pattern for indices to restore from snapshot (comma-separated glob patterns)
6060
indicesPattern: sts*,.ds-sts_k8s_logs*
6161

62+
# StackState platform configuration shared across restore operations
63+
stackstate:
64+
baseUrl: "http://suse-observability-server:7070"
65+
receiverBaseUrl: "http://suse-observability-receiver:7077"
66+
platformVersion: "5.2.0"
67+
6268
# Minio configuration for S3-compatible storage
6369
minio:
6470
enabled: true
@@ -86,6 +92,7 @@ stackgraph:
8692
scaleDownLabelSelector: "observability.suse.com/scalable-during-stackgraph-restore=true"
8793
# ConfigMap containing logging configuration
8894
loggingConfigConfigMap: suse-observability-logging
95+
stsBackupConfigConfigMap: suse-observability-backup-config
8996
# Zookeeper quorum connection string
9097
zookeeperQuorum: "suse-observability-zookeeper:2181"
9198
# Job configuration
@@ -145,9 +152,7 @@ settings:
145152
restore:
146153
scaleDownLabelSelector: "observability.suse.com/scalable-during-settings-restore=true"
147154
loggingConfigConfigMap: suse-observability-logging
148-
baseUrl: "http://suse-observability-server:7070"
149-
receiverBaseUrl: "http://suse-observability-receiver:7077"
150-
platformVersion: "5.2.0"
155+
stsBackupConfigConfigMap: suse-observability-backup-config
151156
zookeeperQuorum: "suse-observability-zookeeper:2181"
152157
pvc: "suse-observability-settings-backup-data"
153158
job:

internal/foundation/config/testdata/validConfigMapOnly.yaml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ elasticsearch:
6666
# Pattern for indices to restore from snapshot (comma-separated glob patterns)
6767
indicesPattern: sts*,.ds-sts_k8s_logs*
6868

69+
stackstate:
70+
baseUrl: "http://suse-observability-server:7070"
71+
receiverBaseUrl: "http://suse-observability-receiver:7077"
72+
platformVersion: "5.2.0"
73+
6974
# Minio configuration for S3-compatible storage
7075
minio:
7176
enabled: true
@@ -83,6 +88,7 @@ stackgraph:
8388
restore:
8489
scaleDownLabelSelector: "observability.suse.com/scalable-during-stackgraph-restore=true"
8590
loggingConfigConfigMap: suse-observability-logging
91+
stsBackupConfigConfigMap: suse-observability-backup-config
8692
zookeeperQuorum: "suse-observability-zookeeper:2181"
8793
job:
8894
labels:
@@ -132,9 +138,7 @@ settings:
132138
restore:
133139
scaleDownLabelSelector: "observability.suse.com/scalable-during-settings-restore=true"
134140
loggingConfigConfigMap: suse-observability-logging
135-
baseUrl: "http://suse-observability-server:7070"
136-
receiverBaseUrl: "http://suse-observability-receiver:7077"
137-
platformVersion: "5.2.0"
141+
stsBackupConfigConfigMap: suse-observability-backup-config
138142
zookeeperQuorum: "suse-observability-zookeeper:2181"
139143
pvc: "suse-observability-settings-backup-data"
140144
job:

internal/foundation/config/testdata/validStorageConfigMapConfig.yaml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ elasticsearch:
6161
# Pattern for indices to restore from snapshot (comma-separated glob patterns)
6262
indicesPattern: sts*,.ds-sts_k8s_logs*
6363

64+
stackstate:
65+
baseUrl: "http://suse-observability-server:7070"
66+
receiverBaseUrl: "http://suse-observability-receiver:7077"
67+
platformVersion: "5.2.0"
68+
6469
# Storage configuration for S3-compatible storage (new mode, replaces Minio)
6570
storage:
6671
globalBackupEnabled: true
@@ -87,6 +92,7 @@ stackgraph:
8792
scaleDownLabelSelector: "observability.suse.com/scalable-during-stackgraph-restore=true"
8893
# ConfigMap containing logging configuration
8994
loggingConfigConfigMap: suse-observability-logging
95+
stsBackupConfigConfigMap: suse-observability-backup-config
9096
# Zookeeper quorum connection string
9197
zookeeperQuorum: "suse-observability-zookeeper:2181"
9298
# Job configuration
@@ -147,9 +153,7 @@ settings:
147153
restore:
148154
scaleDownLabelSelector: "observability.suse.com/scalable-during-settings-restore=true"
149155
loggingConfigConfigMap: suse-observability-logging
150-
baseUrl: "http://suse-observability-server:7070"
151-
receiverBaseUrl: "http://suse-observability-receiver:7077"
152-
platformVersion: "5.2.0"
156+
stsBackupConfigConfigMap: suse-observability-backup-config
153157
zookeeperQuorum: "suse-observability-zookeeper:2181"
154158
job:
155159
labels:

0 commit comments

Comments
 (0)