diff --git a/controllers/storageconsumer/storageconsumer_controller.go b/controllers/storageconsumer/storageconsumer_controller.go index 2a4535a2c2..682075db9c 100644 --- a/controllers/storageconsumer/storageconsumer_controller.go +++ b/controllers/storageconsumer/storageconsumer_controller.go @@ -51,6 +51,7 @@ const ( StorageProfileLabel = "ocs.openshift.io/storageprofile" ConsumerUUIDLabel = "ocs.openshift.io/storageconsumer-uuid" StorageConsumerNameLabel = "ocs.openshift.io/storageconsumer-name" + MaintenanceModeLabel = "ocs.openshift.io/maintenanceMode" ) // StorageConsumerReconciler reconciles a StorageConsumer object diff --git a/controllers/util/util.go b/controllers/util/util.go index 634ad65245..edc967805b 100644 --- a/controllers/util/util.go +++ b/controllers/util/util.go @@ -89,6 +89,19 @@ func AddLabel(obj metav1.Object, key string, value string) bool { return false } +func RemoveLabel(obj metav1.Object, key string) bool { + labels := obj.GetLabels() + if labels == nil { + return false + } + if _, exists := labels[key]; exists { + delete(labels, key) + obj.SetLabels(labels) + return true + } + return false +} + func CalculateMD5Hash(value any) string { data, err := json.Marshal(value) if err != nil { diff --git a/deploy/ocs-operator/manifests/provider-role.yaml b/deploy/ocs-operator/manifests/provider-role.yaml index dd1c692975..d9870dfa00 100644 --- a/deploy/ocs-operator/manifests/provider-role.yaml +++ b/deploy/ocs-operator/manifests/provider-role.yaml @@ -11,6 +11,13 @@ rules: - services verbs: - get + - apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list - apiGroups: - ceph.rook.io resources: diff --git a/metrics/vendor/github.com/red-hat-storage/ocs-operator/v4/controllers/util/util.go b/metrics/vendor/github.com/red-hat-storage/ocs-operator/v4/controllers/util/util.go index 634ad65245..edc967805b 100644 --- a/metrics/vendor/github.com/red-hat-storage/ocs-operator/v4/controllers/util/util.go +++ b/metrics/vendor/github.com/red-hat-storage/ocs-operator/v4/controllers/util/util.go @@ -89,6 +89,19 @@ func AddLabel(obj metav1.Object, key string, value string) bool { return false } +func RemoveLabel(obj metav1.Object, key string) bool { + labels := obj.GetLabels() + if labels == nil { + return false + } + if _, exists := labels[key]; exists { + delete(labels, key) + obj.SetLabels(labels) + return true + } + return false +} + func CalculateMD5Hash(value any) string { data, err := json.Marshal(value) if err != nil { diff --git a/rbac/provider-role.yaml b/rbac/provider-role.yaml index dd1c692975..d9870dfa00 100644 --- a/rbac/provider-role.yaml +++ b/rbac/provider-role.yaml @@ -11,6 +11,13 @@ rules: - services verbs: - get + - apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list - apiGroups: - ceph.rook.io resources: diff --git a/services/provider/server/consumer.go b/services/provider/server/consumer.go index 9e2fe820ee..3e5aaba961 100644 --- a/services/provider/server/consumer.go +++ b/services/provider/server/consumer.go @@ -227,3 +227,11 @@ func (c *ocsConsumerManager) UpdateConsumerStatus(ctx context.Context, id string klog.Infof("successfully updated Status for StorageConsumer %v", consumerObj.Name) return nil } + +func (c *ocsConsumerManager) Update(ctx context.Context, consumer *ocsv1alpha1.StorageConsumer) error { + if err := c.client.Update(ctx, consumer); err != nil { + return fmt.Errorf("failed to update StorageConsumer %v: %v", consumer.Name, err) + } + klog.Infof("successfully updated StorageConsumer %v", consumer.Name) + return nil +} diff --git a/services/provider/server/server.go b/services/provider/server/server.go index 1e7f82ae4a..46457dd00b 100644 --- a/services/provider/server/server.go +++ b/services/provider/server/server.go @@ -11,6 +11,7 @@ import ( "encoding/json" "encoding/pem" "fmt" + appsv1 "k8s.io/api/apps/v1" "math" "net" "slices" @@ -293,6 +294,10 @@ func newScheme() (*runtime.Scheme, error) { if err != nil { return nil, fmt.Errorf("failed to add routev1 to scheme. %v", err) } + err = appsv1.AddToScheme(scheme) + if err != nil { + return nil, fmt.Errorf("failed to add appsv1 to scheme. %v", err) + } return scheme, nil } @@ -928,3 +933,59 @@ func extractMonitorIps(data string) ([]string, error) { func (s *OCSProviderServer) PeerStorageCluster(_ context.Context, _ *pb.PeerStorageClusterRequest) (*pb.PeerStorageClusterResponse, error) { return &pb.PeerStorageClusterResponse{}, nil } + +func (s *OCSProviderServer) StartMaintenanceMode(ctx context.Context, req *pb.StartMaintenanceModeRequest) (*pb.StartMaintenanceModeResponse, error) { + // Get storage consumer resource using UUID + consumer, err := s.consumerManager.Get(ctx, req.StorageConsumerUUID) + if err != nil { + return nil, status.Errorf(codes.Internal, err.Error()) + } + + util.AddLabel(consumer, controllers.MaintenanceModeLabel, "") + err = s.consumerManager.Update(ctx, consumer) + if err != nil { + return nil, status.Errorf(codes.Internal, err.Error()) + } + + return &pb.StartMaintenanceModeResponse{}, nil +} + +func (s *OCSProviderServer) StopMaintenanceMode(ctx context.Context, req *pb.StopMaintenanceModeRequest) (*pb.StopMaintenanceModeResponse, error) { + // Get storage consumer resource using UUID + consumer, err := s.consumerManager.Get(ctx, req.StorageConsumerUUID) + if err != nil { + return nil, status.Errorf(codes.Internal, err.Error()) + } + + util.RemoveLabel(consumer, controllers.MaintenanceModeLabel) + + if err := s.consumerManager.Update(ctx, consumer); err != nil { + return nil, status.Errorf(codes.Internal, err.Error()) + } + + return &pb.StopMaintenanceModeResponse{}, nil +} + +func (s *OCSProviderServer) GetMaintenanceModeStatus(ctx context.Context, req *pb.GetMaintenanceModeStatusRequest) (*pb.GetMaintenanceModeStatusResponse, error) { + // Get storage consumer resource using UUID + _, err := s.consumerManager.Get(ctx, req.StorageConsumerUUID) + if err != nil { + return nil, status.Errorf(codes.Internal, err.Error()) + } + + rbdMirrorDeployments := &appsv1.DeploymentList{} + err = s.client.List(ctx, rbdMirrorDeployments, client.InNamespace(s.namespace), client.MatchingLabels{"app": "rook-ceph-rbd-mirror"}, client.Limit(1)) + if err != nil { + return nil, status.Errorf(codes.Internal, err.Error()) + } + + if len(rbdMirrorDeployments.Items) == 0 { + return nil, fmt.Errorf("no rbd-mirror deployment found") + } + + replicas := rbdMirrorDeployments.Items[0].Status.Replicas + if replicas == 1 { + return &pb.GetMaintenanceModeStatusResponse{MaintenanceStatus: pb.GetMaintenanceModeStatusResponse_Progressing}, nil + } + return &pb.GetMaintenanceModeStatusResponse{MaintenanceStatus: pb.GetMaintenanceModeStatusResponse_Completed}, nil +}