che-operator/controllers/che/backup.go

128 lines
4.4 KiB
Go

//
// Copyright (c) 2021 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
// Red Hat, Inc. - initial API and implementation
//
package che
import (
"context"
"fmt"
"strings"
semver "github.com/blang/semver/v4"
"github.com/sirupsen/logrus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
chev1 "github.com/eclipse-che/che-operator/api/v1"
"github.com/eclipse-che/che-operator/pkg/deploy"
)
const (
DefaultBackupServerConfigLabelKey = "che.eclipse.org/backup-before-update"
)
func isCheGoingToBeUpdated(cheCR *chev1.CheCluster) bool {
deployedCheVersion := cheCR.Status.CheVersion
newCheVersion := deploy.DefaultCheVersion()
if deployedCheVersion == "" || deployedCheVersion == "next" || deployedCheVersion == newCheVersion {
return false
}
deployedSemver, err := semver.Make(deployedCheVersion)
if err != nil {
logrus.Warn(getSemverParseErrorMessage(deployedCheVersion, err))
return false
}
currentSemver, err := semver.Make(newCheVersion)
if err != nil {
logrus.Warn(getSemverParseErrorMessage(newCheVersion, err))
return false
}
return currentSemver.GT(deployedSemver)
}
func getSemverParseErrorMessage(version string, err error) string {
return fmt.Sprintf("It is not possible to parse a version '%s'. Cause: %v", version, err)
}
// getBackupCRForUpdate returns backup CR that corresponds to the backup made before updating to a new Che version.
func getBackupCRForUpdate(deployContext *deploy.DeployContext) (*chev1.CheClusterBackup, error) {
backupCR := &chev1.CheClusterBackup{}
backupCRName := getBackupCRNameForVersion(deploy.DefaultCheVersion())
backupCRNamespacedName := types.NamespacedName{Namespace: deployContext.CheCluster.GetNamespace(), Name: backupCRName}
if err := deployContext.ClusterAPI.Client.Get(context.TODO(), backupCRNamespacedName, backupCR); err != nil {
return nil, err
}
return backupCR, nil
}
func getBackupCRNameForVersion(version string) string {
return "backup-before-update-to-" + strings.Replace(version, ".", "-", -1)
}
func requestBackup(deployContext *deploy.DeployContext) error {
backupCR, err := getBackupCRSpec(deployContext)
if err != nil {
return err
}
return deployContext.ClusterAPI.Client.Create(context.TODO(), backupCR)
}
func getBackupCRSpec(deployContext *deploy.DeployContext) (*chev1.CheClusterBackup, error) {
backupServerConfigName, err := getBackupServerConfigurationNameForBackupBeforeUpdate(deployContext)
if err != nil {
return nil, err
}
cheClusterBackupSpec := chev1.CheClusterBackupSpec{}
if backupServerConfigName == "" {
cheClusterBackupSpec.UseInternalBackupServer = true
} else {
cheClusterBackupSpec.UseInternalBackupServer = false
cheClusterBackupSpec.BackupServerConfigRef = backupServerConfigName
}
return &chev1.CheClusterBackup{
TypeMeta: metav1.TypeMeta{
Kind: "CheClusterBackup",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: getBackupCRNameForVersion(deploy.DefaultCheVersion()),
Namespace: deployContext.CheCluster.GetNamespace(),
},
Spec: cheClusterBackupSpec,
}, nil
}
// getBackupServerConfigurationNameForBackupBeforeUpdate searches for backup server configuration.
// If there is only one, then it is used.
// If there are two or more, then one with 'che.eclipse.org/default-backup-server-configuration' annotation is used.
// If there is none, then empty string is returned.
func getBackupServerConfigurationNameForBackupBeforeUpdate(deployContext *deploy.DeployContext) (string, error) {
backupServerConfigsList := &chev1.CheBackupServerConfigurationList{}
listOptions := &client.ListOptions{
Namespace: deployContext.CheCluster.GetNamespace(),
}
if err := deployContext.ClusterAPI.Client.List(context.TODO(), backupServerConfigsList, listOptions); err != nil {
return "", err
}
if len(backupServerConfigsList.Items) == 1 {
return backupServerConfigsList.Items[0].GetName(), nil
}
for _, backupServerConfig := range backupServerConfigsList.Items {
if backupServerConfig.ObjectMeta.Annotations != nil && backupServerConfig.ObjectMeta.Annotations[DefaultBackupServerConfigLabelKey] == "true" {
return backupServerConfig.GetName(), nil
}
}
return "", nil
}