Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow users to take GCS-based backups #302

Merged
merged 23 commits into from
Sep 27, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
8e6f69d
Allow users to take GCS-based backups
gerlowskija Aug 5, 2021
93371f1
Reject GCS backups for Solr < 8.9.0
gerlowskija Aug 10, 2021
999b687
Address initial review feedback
gerlowskija Aug 13, 2021
998a311
Review feedback, rd 2
gerlowskija Sep 13, 2021
5d85c94
Fix persistence-status updating bug
gerlowskija Sep 14, 2021
ad48018
Address lint error, rd 1
gerlowskija Sep 14, 2021
e871fc9
Add unit tests for backup helpers
gerlowskija Sep 15, 2021
696e5d3
Add YAML examples for various backup scenarios
gerlowskija Sep 15, 2021
290b720
Refresh README for solrbackups
gerlowskija Sep 16, 2021
84c3eda
Remove some personal debug logging
gerlowskija Sep 16, 2021
dfc805e
Fix lint errors, rd 2
gerlowskija Sep 16, 2021
97616ff
Change syntax of backupRepos - first pass
HoustonPutman Sep 23, 2021
1dab4ec
Fix formatting issues.
HoustonPutman Sep 23, 2021
9a24015
Default the legacy-backup-repo and move it to the new location
HoustonPutman Sep 23, 2021
bb99f9c
Add documentation for the new backup features and upgrade.
HoustonPutman Sep 23, 2021
65d7fcb
Add a few more tests. Add messages for all tests. Refactor locaiton o…
HoustonPutman Sep 24, 2021
4cfaf80
Add changelog entry. Add Backup examples in helm chart metadata
HoustonPutman Sep 24, 2021
2665aa4
Add more to the deprecation warning. Add new option in Helm chart.
HoustonPutman Sep 24, 2021
668d1c3
Merge branch 'main' into 301_gcs_backup_support
HoustonPutman Sep 24, 2021
411373c
Fix manifests
HoustonPutman Sep 24, 2021
ac5e79a
Fix default permissions for volumes & backupIsReady status
HoustonPutman Sep 27, 2021
2b29fd9
Rename example backup files
HoustonPutman Sep 27, 2021
39e386c
Formatting
HoustonPutman Sep 27, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion api/v1beta1/solrbackup_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@ type SolrBackupSpec struct {
// A reference to the SolrCloud to create a backup for
SolrCloud string `json:"solrCloud"`

// The name of the repository to use for the backup. Defaults to "legacy_local_repository" if not specified (the
// auto-configured repository for legacy singleton volumes).
RepositoryName string `json:"repositoryName,omitempty"`
gerlowskija marked this conversation as resolved.
Show resolved Hide resolved

// The list of collections to backup. If empty, all collections in the cloud will be backed up.
// +optional
Collections []string `json:"collections,omitempty"`

// Persistence is the specification on how to persist the backup data.
Persistence PersistenceSource `json:"persistence"`
Persistence PersistenceSource `json:"persistence,omitempty"`
gerlowskija marked this conversation as resolved.
Show resolved Hide resolved
}

func (spec *SolrBackupSpec) withDefaults(backupName string) (changed bool) {
Expand Down
158 changes: 150 additions & 8 deletions api/v1beta1/solrcloud_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,13 @@ package v1beta1

import (
"fmt"
"strconv"
"strings"

"k8s.io/apimachinery/pkg/util/intstr"

zk "github.com/pravega/zookeeper-operator/pkg/apis/zookeeper/v1beta1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"strconv"
"strings"
)

const (
Expand Down Expand Up @@ -55,6 +53,12 @@ const (
ZookeeperTechnologyLabel = "zookeeper"

DefaultBasicAuthUsername = "k8s-oper"

DefaultBackupRepositoryName = "legacy_local_repository"
BaseBackupRestorePath = "/var/solr/data/backup-restore"
BackupRestoreInitContainerPath = "/backup-restore"
BackupRestoreVolume = "backup-restore"
BackupRestoreCredentialVolume = "backup-restore-credential"
)

// SolrCloudSpec defines the desired state of SolrCloud
Expand Down Expand Up @@ -217,7 +221,7 @@ type SolrDataStorageOptions struct {
// +optional
EphemeralStorage *SolrEphemeralDataStorageOptions `json:"ephemeral,omitempty"`

// Options required for backups & restores to be enabled for this solrCloud.
// Options required for backups to be enabled for this solrCloud.
// +optional
BackupRestoreOptions *SolrBackupRestoreOptions `json:"backupRestoreOptions,omitempty"`
}
Expand Down Expand Up @@ -325,20 +329,158 @@ type SolrEphemeralDataStorageOptions struct {
EmptyDir *corev1.EmptyDirVolumeSource `json:"emptyDir,omitempty"`
}

func (backupOptions *SolrBackupRestoreOptions) IsManaged() bool {
return true
}

func (backupOptions *SolrBackupRestoreOptions) GetVolumeSource() corev1.VolumeSource {
return *backupOptions.Volume
}

func (backupOptions *SolrBackupRestoreOptions) GetDirectory() string {
return backupOptions.Directory
}

func (backupOptions *SolrBackupRestoreOptions) GetSolrMountPath() string {
return BaseBackupRestorePath
}

func (backupOptions *SolrBackupRestoreOptions) GetInitPodMountPath() string {
return BackupRestoreInitContainerPath
}

func (backupOptions *SolrBackupRestoreOptions) GetBackupPath(backupName string) string {
return backupOptions.GetSolrMountPath() + "/backups/" + backupName
}

func (backupOptions *SolrBackupRestoreOptions) GetVolumeName() string {
return BackupRestoreVolume
}

type SolrBackupRestoreOptions struct {
// TODO Do we need to support this (Volume) here for backcompat, or can it live exclusively in ManagedStorage?
HoustonPutman marked this conversation as resolved.
Show resolved Hide resolved

// This is a volumeSource for a volume that will be mounted to all solrNodes to store backups and load restores.
// The data within the volume will be namespaces for this instance, so feel free to use the same volume for multiple clouds.
// Since the volume will be mounted to all solrNodes, it must be able to be written from multiple pods.
// If a PVC reference is given, the PVC must have `accessModes: - ReadWriteMany`.
// Other options are to use a NFS volume.
Volume corev1.VolumeSource `json:"volume"`
Volume *corev1.VolumeSource `json:"volume,omitempty"`

// Allows specification of multiple different "repositories" for Solr to use when backing up data to GCS.
GcsRepositories *[]GcsStorage `json:"gcsRepositories,omitempty"`
HoustonPutman marked this conversation as resolved.
Show resolved Hide resolved

// Allows specification of multiple different "repositories" for Solr to use when backing up data "locally".
// Repositories defined here are considered "managed" and can take advantage of special operator features, such as
// post-backup compression.
ManagedRepositories *[]ManagedStorage `json:"managedRepositories,omitempty""`

// TODO Do we need to support this here for backcompat, or can it live exclusively in ManagedStorage
// Select a custom directory name to mount the backup/restore data from the given volume.
// If not specified, then the name of the solrcloud will be used by default.
// +optional
Directory string `json:"directory,omitempty"`
}

type GcsStorage struct {
// A name used to identify this GCS storage profile.
Name string `json:"name"`

// The name of the GCS bucket that all backup data will be stored in
Bucket string `json:"bucket"`

// The name of a Kubernetes secret holding a Google cloud service account key
GcsCredentialSecret string `json:"gcsCredentialSecret"`
HoustonPutman marked this conversation as resolved.
Show resolved Hide resolved
// JEGERLOW TODO Should 'baseLocation' be optional?
// A chroot within the bucket to store data in. If specified this should already exist
BaseLocation string `json:"baseLocation"`
gerlowskija marked this conversation as resolved.
Show resolved Hide resolved
}

func VolumeExistsWithName(needle string, haystack []corev1.Volume) bool {
for _, volume := range haystack {
if volume.Name == needle {
return true
}
}
return false
}

func (gcsRepository *GcsStorage) IsManaged() bool { return false }

func (gcsRepository *GcsStorage) GetSolrMountPath() string {
return fmt.Sprintf("%s-%s-%s", BaseBackupRestorePath, "gcscredential", gcsRepository.Name)
}

func (gcsRepository *GcsStorage) GetInitPodMountPath() string {
return ""
}

func (gcsRepository *GcsStorage) GetBackupPath(backupName string) string {
if gcsRepository.BaseLocation != "" {
return gcsRepository.BaseLocation
}
return "/"
}

func (gcsRepository *GcsStorage) GetVolumeName() string {
return fmt.Sprintf("%s-%s", gcsRepository.Name, BackupRestoreCredentialVolume)
}

func (gcs *GcsStorage) IsCredentialVolumePresent(volumes []corev1.Volume) bool {
expectedVolumeName := gcs.GetVolumeName()
return VolumeExistsWithName(expectedVolumeName, volumes)
}

type ManagedStorage struct {
// A name used to identify this local storage profile.
Name string `json:"name"`

// This is a volumeSource for a volume that will be mounted to all solrNodes to store backups and load restores.
// The data within the volume will be namespaces for this instance, so feel free to use the same volume for multiple clouds.
// Since the volume will be mounted to all solrNodes, it must be able to be written from multiple pods.
// If a PVC reference is given, the PVC must have `accessModes: - ReadWriteMany`.
// Other options are to use a NFS volume.
Volume *corev1.VolumeSource `json:"volume,omitempty"`
gerlowskija marked this conversation as resolved.
Show resolved Hide resolved

// Select a custom directory name to mount the backup/restore data from the given volume.
// If not specified, then the name of the solrcloud will be used by default.
// +optional
Directory string `json:"directory,omitempty"`
}

func (managedRepository *ManagedStorage) IsManaged() bool { return true }
gerlowskija marked this conversation as resolved.
Show resolved Hide resolved

func (managedRepository *ManagedStorage) GetVolumeSource() corev1.VolumeSource {
return *managedRepository.Volume
}

func (managedRepository *ManagedStorage) GetDirectory() string {
return managedRepository.Directory
}

func (managedRepository *ManagedStorage) GetSolrMountPath() string {
return fmt.Sprintf("%s-%s-%s", BaseBackupRestorePath, "managed", managedRepository.Name)
}

func (managedRepository *ManagedStorage) GetInitPodMountPath() string {
return fmt.Sprintf("/backup-restore-managed-%s", managedRepository.Name)
}

func (managedRepository *ManagedStorage) GetBackupPath(backupName string) string {
return managedRepository.GetSolrMountPath() + "/backups/" + backupName
}

func (managedRepository *ManagedStorage) GetVolumeName() string {
return fmt.Sprintf("%s-%s", managedRepository.Name, BackupRestoreVolume)
}

// TODO JEGERLOW: Is this the most natural place for this? 'IsDataVolumePresent' seems like a method that'd fit
// better on 'pod' and take in a ManagedStorage
func (managedRepository *ManagedStorage) IsBackupVolumePresent(volumes []corev1.Volume) bool {
expectedVolumeName := managedRepository.GetVolumeName()
return VolumeExistsWithName(expectedVolumeName, volumes)
}

type SolrAddressabilityOptions struct {
// External defines the way in which this SolrCloud nodes should be made addressable externally, from outside the Kubernetes cluster.
// If none is provided, the Solr Cloud will not be made addressable externally.
Expand Down Expand Up @@ -1140,4 +1282,4 @@ type SolrSecurityOptions struct {
// endpoints with credentials sourced from an env var instead of HTTP directly.
// +optional
ProbesRequireAuth bool `json:"probesRequireAuth,omitempty"`
}
}
61 changes: 60 additions & 1 deletion api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion config/crd/bases/solr.apache.org_solrbackups.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1048,11 +1048,13 @@ spec:
- source
type: object
type: object
repositoryName:
description: The name of the repository to use for the backup. Defaults to "legacy_local_repository" if not specified (the auto-configured repository for legacy singleton volumes).
type: string
solrCloud:
description: A reference to the SolrCloud to create a backup for
type: string
required:
- persistence
- solrCloud
type: object
status:
Expand Down
Loading