Files
my-rook-config/pkg/operator/ceph/cluster/version.go
T
parth-gr 26584fc6e5 core: update loadclusterInfo with multus check
if Multus is enabled the clusterinfo should be updated with
network as multus as to run the ceph cmds in remote
executor

Signed-off-by: parth-gr <paarora@redhat.com>
2022-09-22 14:46:51 +05:30

212 lines
8.1 KiB
Go

/*
Copyright 2020 The Rook Authors. All rights reserved.
Licensed 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 cluster to manage a Ceph cluster.
package cluster
import (
"github.com/pkg/errors"
cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
daemonclient "github.com/rook/rook/pkg/daemon/ceph/client"
"github.com/rook/rook/pkg/operator/ceph/cluster/mon"
"github.com/rook/rook/pkg/operator/ceph/controller"
cephver "github.com/rook/rook/pkg/operator/ceph/version"
)
func (c *ClusterController) detectAndValidateCephVersion(cluster *cluster) (*cephver.CephVersion, bool, error) {
version, err := controller.DetectCephVersion(
c.OpManagerCtx,
c.rookImage,
cluster.Namespace,
detectVersionName,
cluster.ownerInfo,
c.context.Clientset,
cluster.Spec,
)
if err != nil {
return nil, false, err
}
logger.Info("validating ceph version from provided image")
if err := cluster.validateCephVersion(version); err != nil {
return nil, cluster.isUpgrade, err
}
// Update ceph version field in cluster object status
c.updateClusterCephVersion(cluster.Spec.CephVersion.Image, *version)
return version, cluster.isUpgrade, nil
}
func (c *cluster) printOverallCephVersion() {
versions, err := daemonclient.GetAllCephDaemonVersions(c.context, c.ClusterInfo)
if err != nil {
logger.Errorf("failed to get ceph daemons versions. %v", err)
return
}
if len(versions.Overall) == 1 {
for v := range versions.Overall {
version, err := cephver.ExtractCephVersion(v)
if err != nil {
logger.Errorf("failed to extract ceph version. %v", err)
return
}
vv := *version
logger.Infof("successfully upgraded cluster to version: %q", vv.String())
}
} else {
// This shouldn't happen, but let's log just in case
logger.Warningf("upgrade orchestration completed but somehow we still have more than one Ceph version running. %v:", versions.Overall)
}
}
// This function compare the Ceph spec image and the cluster running version
// It returns true if the image is different and false if identical
func diffImageSpecAndClusterRunningVersion(imageSpecVersion cephver.CephVersion, runningVersions cephv1.CephDaemonsVersions) (bool, error) {
numberOfCephVersions := len(runningVersions.Overall)
if numberOfCephVersions == 0 {
// let's return immediately
return false, errors.Errorf("no 'overall' section in the ceph versions. %+v", runningVersions.Overall)
}
if numberOfCephVersions > 1 {
// let's return immediately
logger.Warningf("it looks like we have more than one ceph version running. triggering upgrade. %+v:", runningVersions.Overall)
return true, nil
}
if numberOfCephVersions == 1 {
for v := range runningVersions.Overall {
version, err := cephver.ExtractCephVersion(v)
if err != nil {
logger.Errorf("failed to extract ceph version. %v", err)
return false, err
}
clusterRunningVersion := *version
// If this is the same version
if cephver.IsIdentical(clusterRunningVersion, imageSpecVersion) {
logger.Debugf("both cluster and image spec versions are identical, doing nothing %s", imageSpecVersion.String())
return false, nil
}
if cephver.IsSuperior(imageSpecVersion, clusterRunningVersion) {
logger.Infof("image spec version %s is higher than the running cluster version %s, upgrading", imageSpecVersion.String(), clusterRunningVersion.String())
return true, nil
}
if cephver.IsInferior(imageSpecVersion, clusterRunningVersion) {
logger.Warningf("image spec version %s is lower than the running cluster version %s, downgrading is not supported", imageSpecVersion.String(), clusterRunningVersion.String())
return true, nil
}
}
}
return false, nil
}
func (c *cluster) validateCephVersion(version *cephver.CephVersion) error {
if !c.Spec.External.Enable {
if !version.IsAtLeast(cephver.Minimum) {
return errors.Errorf("the version does not meet the minimum version %q", cephver.Minimum.String())
}
if !version.Supported() {
if !c.Spec.CephVersion.AllowUnsupported {
return errors.Errorf("allowUnsupported must be set to true to run with this version %q", version.String())
}
logger.Warningf("unsupported ceph version detected: %q, pursuing", version)
}
if version.Unsupported() {
logger.Errorf("UNSUPPORTED: ceph version %q detected, it is recommended to rollback to the previous pin-point stable release, pursuing anyways", version)
}
}
// The following tries to determine if the operator can proceed with an upgrade because we come from an OnAdd() call
// If the cluster was unhealthy and someone injected a new image version, an upgrade was triggered but failed because the cluster is not healthy
// Then after this, if the operator gets restarted we are not able to fail if the cluster is not healthy, the following tries to determine the
// state we are in and if we should upgrade or not
// Try to load clusterInfo so we can compare the running version with the one from the spec image
clusterInfo, _, _, err := controller.LoadClusterInfo(c.context, c.ClusterInfo.Context, c.Namespace, c.Spec)
if err == nil {
clusterInfo.Context = c.ClusterInfo.Context
// Write connection info (ceph config file and keyring) for ceph commands
err = mon.WriteConnectionConfig(c.context, clusterInfo)
if err != nil {
logger.Errorf("failed to write config. attempting to continue. %v", err)
}
}
if err := clusterInfo.IsInitialized(); err != nil {
// If not initialized, this is likely a new cluster so there is nothing to do
logger.Debugf("cluster not initialized, nothing to validate. %v", err)
return nil
}
clusterInfo.CephVersion = *version
if c.Spec.External.Enable && c.Spec.CephVersion.Image != "" {
c.ClusterInfo.CephVersion, err = controller.ValidateCephVersionsBetweenLocalAndExternalClusters(c.context, c.ClusterInfo)
if err != nil {
return errors.Wrap(err, "failed to validate ceph version between external and local")
}
}
// On external cluster setup, if we don't bootstrap any resources in the Kubernetes cluster then
// there is no need to validate the Ceph image further
if c.Spec.External.Enable && c.Spec.CephVersion.Image == "" {
logger.Debug("no spec image specified on external cluster, not validating Ceph version.")
return nil
}
// Get cluster running versions
versions, err := daemonclient.GetAllCephDaemonVersions(c.context, c.ClusterInfo)
if err != nil {
logger.Errorf("failed to get ceph daemons versions, this typically happens during the first cluster initialization. %v", err)
return nil
}
runningVersions := *versions
differentImages, err := diffImageSpecAndClusterRunningVersion(*version, runningVersions)
if err != nil {
logger.Errorf("failed to determine if we should upgrade or not. %v", err)
// we shouldn't block the orchestration if we can't determine the version of the image spec, we proceed anyway in best effort
// we won't be able to check if there is an update or not and what to do, so we don't check the cluster status either
// This will happen if someone uses ceph/daemon:latest-master for instance
return nil
}
if differentImages {
// If the image version changed let's make sure we can safely upgrade
// check ceph's status, if not healthy we fail
cephHealthy := daemonclient.IsCephHealthy(c.context, c.ClusterInfo)
if !cephHealthy {
if c.Spec.SkipUpgradeChecks {
logger.Warning("ceph is not healthy but SkipUpgradeChecks is set, forcing upgrade.")
} else {
return errors.Errorf("ceph status in namespace %s is not healthy, refusing to upgrade. Either fix the health issue or force an update by setting skipUpgradeChecks to true in the cluster CR", c.Namespace)
}
}
// This is an upgrade
logger.Infof("upgrading ceph cluster to %q", version.String())
c.isUpgrade = true
}
return nil
}