Files
my-rook-config/pkg/operator/ceph/config/conditions.go
T
Nizamudeen 3296fc64a9 ceph: Follow up for adding the state variable
Changed back the status.State to the exact way it was implemented on the ceph cluster. Added the States as a Constant and used that constant to call the status.State.

Signed-off-by: Nizamudeen <nia@redhat.com>
2020-03-04 18:57:07 +05:30

206 lines
7.2 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 config to provide conditions for CephCluster
package config
import (
"time"
"github.com/pkg/errors"
cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
"github.com/rook/rook/pkg/clusterd"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var (
conditions *[]cephv1.Condition
conditionMap = make(map[cephv1.ConditionType]v1.ConditionStatus)
)
// ConditionExport function will export each condition into the cluster custom resource
func ConditionExport(context *clusterd.Context, namespace, name string, conditionType cephv1.ConditionType, status v1.ConditionStatus, reason, message string) {
setCondition(context, namespace, name, cephv1.Condition{
Type: conditionType,
Status: status,
Reason: reason,
Message: message,
})
}
// setCondition updates the conditions of the cluster custom resource
func setCondition(context *clusterd.Context, namespace, name string, newCondition cephv1.Condition) {
cluster, err := context.RookClientset.CephV1().CephClusters(namespace).Get(name, metav1.GetOptions{})
if err != nil {
logger.Errorf("failed to get cluster %v", err)
}
if conditions == nil {
conditions = &cluster.Status.Conditions
if cluster.Status.Conditions != nil {
conditionMapping(*conditions)
}
}
conditionMap[newCondition.Type] = newCondition.Status
existingCondition := findStatusCondition(*conditions, newCondition.Type)
if existingCondition == nil {
newCondition.LastTransitionTime = metav1.NewTime(time.Now())
newCondition.LastHeartbeatTime = metav1.NewTime(time.Now())
*conditions = append(*conditions, newCondition)
} else if existingCondition.Status != newCondition.Status || existingCondition.Message != newCondition.Message {
newCondition.LastTransitionTime = metav1.NewTime(time.Now())
existingCondition.Status = newCondition.Status
existingCondition.Reason = newCondition.Reason
existingCondition.Message = newCondition.Message
existingCondition.LastHeartbeatTime = metav1.NewTime(time.Now())
}
cluster.Status.Conditions = *conditions
if newCondition.Status == v1.ConditionTrue {
cluster.Status.Phase = newCondition.Type
if state := translatePhasetoState(newCondition.Type); state != "" {
cluster.Status.State = state
}
cluster.Status.Message = newCondition.Message
logger.Infof("CephCluster %q status: %q. %q", namespace, cluster.Status.Phase, cluster.Status.Message)
}
if _, err := context.RookClientset.CephV1().CephClusters(namespace).Update(cluster); err != nil {
logger.Errorf("failed to update cluster condition %v", err)
}
if newCondition.Type == cephv1.ConditionReady {
checkConditionFalse(context, namespace, name)
}
}
// translatePhasetoState convert the Phases to corresponding State
// 1. We still need to set the State in case someone is still using it
// instead of Phase. If we stopped setting the State it would be a
// breaking change.
// 2. We can't change the enum values of the State since that is also
// a breaking change. Therefore, we translate new phases to the original
// State values
func translatePhasetoState(phase cephv1.ConditionType) cephv1.ClusterState {
switch phase {
case cephv1.ConditionConnecting:
return cephv1.ClusterStateConnecting
case cephv1.ConditionConnected:
return cephv1.ClusterStateConnected
case cephv1.ConditionFailure:
return cephv1.ClusterStateError
case cephv1.ConditionIgnored:
return cephv1.ClusterStateError
case cephv1.ConditionProgressing:
return cephv1.ClusterStateCreating
case cephv1.ConditionReady:
return cephv1.ClusterStateCreated
case cephv1.ConditionUpgrading:
return cephv1.ClusterStateUpdating
case cephv1.ConditionUpdating:
return cephv1.ClusterStateUpdating
default:
return ""
}
}
// Updating the status of Progressing, Updating or Upgrading to False once cluster is Ready
func checkConditionFalse(context *clusterd.Context, namespace, name string) {
tempConditionList := []cephv1.ConditionType{cephv1.ConditionUpdating, cephv1.ConditionUpgrading, cephv1.ConditionProgressing}
var tempCondition cephv1.ConditionType
for _, conditionType := range tempConditionList {
if conditionMap[conditionType] == v1.ConditionTrue {
tempCondition = conditionType
}
}
reason := ""
message := ""
if tempCondition == cephv1.ConditionUpdating {
reason = "UpdateCompleted"
message = "Cluster updating is completed"
} else if tempCondition == cephv1.ConditionUpgrading {
reason = "UpgradeCompleted"
message = "Cluster upgrading is completed"
} else {
reason = "ProgressingCompleted"
message = "Cluster progression is completed"
}
ConditionExport(context, namespace, name, tempCondition, v1.ConditionFalse, reason, message)
}
// ConditionInitialize initializes some of the conditions at the beginning of cluster creation
func ConditionInitialize(context *clusterd.Context, namespace, name string) {
setCondition(context, namespace, name, cephv1.Condition{
Type: cephv1.ConditionFailure,
Status: v1.ConditionFalse,
Reason: "",
Message: "",
})
setCondition(context, namespace, name, cephv1.Condition{
Type: cephv1.ConditionIgnored,
Status: v1.ConditionFalse,
Reason: "",
Message: "",
})
setCondition(context, namespace, name, cephv1.Condition{
Type: cephv1.ConditionUpgrading,
Status: v1.ConditionFalse,
Reason: "",
Message: "",
})
}
// conditionMapping maps the condition type to its status
func conditionMapping(conditions []cephv1.Condition) {
for i := range conditions {
conditionType := conditions[i].Type
conditionMap[conditionType] = conditions[i].Status
}
}
// CheckConditionReady checks whether the cluster is Ready and returns the message for the Progressing ConditionType
func CheckConditionReady(context *clusterd.Context, namespace, name string) string {
cluster, err := context.RookClientset.CephV1().CephClusters(namespace).Get(name, metav1.GetOptions{})
if err != nil {
logger.Errorf("failed to get cluster %v", err)
}
if cluster.Status.Conditions != nil && len(conditionMap) == 0 {
conditionMapping(cluster.Status.Conditions)
}
if conditionMap[cephv1.ConditionReady] == v1.ConditionTrue {
return "Cluster is checking if updates are needed"
}
return "Cluster is creating"
}
// ErrorMapping iterate through the Condition Map to see if Failure is True or False
func ErrorMapping() error {
if conditionMap[cephv1.ConditionFailure] == v1.ConditionTrue {
return errors.New("failed to initialize the cluster")
}
return nil
}
//findStatusCondition is used to find the already existing Condition Type
func findStatusCondition(conditions []cephv1.Condition, conditionType cephv1.ConditionType) *cephv1.Condition {
for i := range conditions {
if conditions[i].Type == conditionType {
return &conditions[i]
}
}
return nil
}