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 11 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
117 changes: 117 additions & 0 deletions api/v1beta1/solr_cloud_type_helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package v1beta1

import (
"fmt"
"k8s.io/api/core/v1"
)

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

func (backupOptions *SolrBackupRestoreOptions) GetVolumeSource() v1.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
}

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 (managedRepository *ManagedStorage) IsManaged() bool { return true }

func (managedRepository *ManagedStorage) GetVolumeSource() v1.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)
}

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

func (managedRepository *ManagedStorage) IsBackupVolumePresent(volumes []v1.Volume) bool {
expectedVolumeName := managedRepository.GetVolumeName()
return VolumeExistsWithName(expectedVolumeName, volumes)
}

func VolumeExistsWithName(needle string, haystack []v1.Volume) bool {
for _, volume := range haystack {
if volume.Name == needle {
return true
}
}
return false
}
12 changes: 10 additions & 2 deletions api/v1beta1/solrbackup_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,24 @@ 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).
// +optional
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"`
// +optional
Persistence *PersistenceSource `json:"persistence,omitempty"`
}

func (spec *SolrBackupSpec) withDefaults(backupName string) (changed bool) {
changed = spec.Persistence.withDefaults(backupName) || changed
if spec.Persistence != nil {
changed = spec.Persistence.withDefaults(backupName) || changed
}

return changed
}
Expand Down
61 changes: 54 additions & 7 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 @@ -331,7 +335,50 @@ type SolrBackupRestoreOptions struct {
// 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"`
// Deprecated: Create an explicit 'managedRepositories' entry instead.
HoustonPutman marked this conversation as resolved.
Show resolved Hide resolved
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"`
HoustonPutman 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.
// Deprecated: Create an explicit 'managedRepositories' entry instead.
// +optional
Directory string `json:"directory,omitempty"`
}

type GcsStorage struct {
// A name used to identify this GCS storage profile. Values should follow RFC-1123. (See here for more details:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-label-names)
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
// An already-created chroot within the bucket to store data in. Defaults to the root path "/" if not specified.
// +optional
BaseLocation string `json:"baseLocation,omitempty"`
}

type ManagedStorage struct {
// A name used to identify this local storage profile. Values should follow RFC-1123. (See here for more details:
// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-label-names)
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 namespaced 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"`

// 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.
Expand Down
67 changes: 65 additions & 2 deletions 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