mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-11-22 14:20:19 +00:00
rbd: enabe journal based mirroring
Journal-based RADOS block device mirroring ensures point-in-time consistent replicas of all changes to an image, including reads and writes, block device resizing, snapshots, clones, and flattening. Journaling-based mirroring records all modifications to an image in the order in which they occur. This ensures that a crash-consistent mirror of an image is available. Mirroring when configured in journal mode, mirroring will utilize the RBD journaling image feature to replicate the image contents. If the RBD journaling image feature is not yet enabled on the image, it will be automatically enabled. Fixes: #2018 Co-authored-by: Madhu Rajanna <madhupr007@gmail.com> Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
This commit is contained in:
parent
ab76459e87
commit
e7d8834149
@ -43,6 +43,9 @@ const (
|
|||||||
// imageMirrorModeSnapshot uses snapshots to propagate RBD images between
|
// imageMirrorModeSnapshot uses snapshots to propagate RBD images between
|
||||||
// ceph clusters.
|
// ceph clusters.
|
||||||
imageMirrorModeSnapshot imageMirroringMode = "snapshot"
|
imageMirrorModeSnapshot imageMirroringMode = "snapshot"
|
||||||
|
// imageMirrorModeJournal uses journaling to propagate RBD images between
|
||||||
|
// ceph clusters.
|
||||||
|
imageMirrorModeJournal imageMirroringMode = "journal"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -123,6 +126,8 @@ func getMirroringMode(ctx context.Context, parameters map[string]string) (librbd
|
|||||||
switch imageMirroringMode(val) {
|
switch imageMirroringMode(val) {
|
||||||
case imageMirrorModeSnapshot:
|
case imageMirrorModeSnapshot:
|
||||||
mirroringMode = librbd.ImageMirrorModeSnapshot
|
mirroringMode = librbd.ImageMirrorModeSnapshot
|
||||||
|
case imageMirrorModeJournal:
|
||||||
|
mirroringMode = librbd.ImageMirrorModeJournal
|
||||||
default:
|
default:
|
||||||
return mirroringMode, status.Errorf(codes.InvalidArgument, "%s %s not supported", imageMirroringKey, val)
|
return mirroringMode, status.Errorf(codes.InvalidArgument, "%s %s not supported", imageMirroringKey, val)
|
||||||
}
|
}
|
||||||
@ -133,12 +138,24 @@ func getMirroringMode(ctx context.Context, parameters map[string]string) (librbd
|
|||||||
// validateSchedulingDetails gets the mirroring mode and scheduling details from the
|
// validateSchedulingDetails gets the mirroring mode and scheduling details from the
|
||||||
// input GRPC request parameters and validates the scheduling is only supported
|
// input GRPC request parameters and validates the scheduling is only supported
|
||||||
// for snapshot mirroring mode.
|
// for snapshot mirroring mode.
|
||||||
func validateSchedulingDetails(parameters map[string]string) error {
|
func validateSchedulingDetails(ctx context.Context, parameters map[string]string) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
val := parameters[imageMirroringKey]
|
val := parameters[imageMirroringKey]
|
||||||
|
|
||||||
switch imageMirroringMode(val) {
|
switch imageMirroringMode(val) {
|
||||||
|
case imageMirrorModeJournal:
|
||||||
|
// journal mirror mode does not require scheduling parameters
|
||||||
|
if _, ok := parameters[schedulingIntervalKey]; ok {
|
||||||
|
log.WarningLog(ctx, "%s parameter cannot be used with %s mirror mode, ignoring it",
|
||||||
|
schedulingIntervalKey, string(imageMirrorModeJournal))
|
||||||
|
}
|
||||||
|
if _, ok := parameters[schedulingStartTimeKey]; ok {
|
||||||
|
log.WarningLog(ctx, "%s parameter cannot be used with %s mirror mode, ignoring it",
|
||||||
|
schedulingStartTimeKey, string(imageMirrorModeJournal))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
case imageMirrorModeSnapshot:
|
case imageMirrorModeSnapshot:
|
||||||
// If mirroring mode is not set in parameters, we are defaulting mirroring
|
// If mirroring mode is not set in parameters, we are defaulting mirroring
|
||||||
// mode to snapshot. Discard empty mirroring mode from validation as it is
|
// mode to snapshot. Discard empty mirroring mode from validation as it is
|
||||||
@ -206,7 +223,7 @@ func (rs *ReplicationServer) EnableVolumeReplication(ctx context.Context,
|
|||||||
}
|
}
|
||||||
defer cr.DeleteCredentials()
|
defer cr.DeleteCredentials()
|
||||||
|
|
||||||
err = validateSchedulingDetails(req.GetParameters())
|
err = validateSchedulingDetails(ctx, req.GetParameters())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -325,10 +342,12 @@ func tickleMirroringOnDummyImage(rbdVol *rbdVolume, mirroringMode librbd.ImageMi
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mirroringMode == librbd.ImageMirrorModeSnapshot {
|
||||||
err = dummyVol.addSnapshotScheduling(admin.Interval("1m"), admin.NoStartTime)
|
err = dummyVol.addSnapshotScheduling(admin.Interval("1m"), admin.NoStartTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package rbd
|
package rbd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -73,6 +74,7 @@ func TestValidateSchedulingInterval(t *testing.T) {
|
|||||||
|
|
||||||
func TestValidateSchedulingDetails(t *testing.T) {
|
func TestValidateSchedulingDetails(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
ctx := context.TODO()
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
parameters map[string]string
|
parameters map[string]string
|
||||||
@ -98,10 +100,10 @@ func TestValidateSchedulingDetails(t *testing.T) {
|
|||||||
{
|
{
|
||||||
"when mirroring mode is journal",
|
"when mirroring mode is journal",
|
||||||
map[string]string{
|
map[string]string{
|
||||||
imageMirroringKey: "journal",
|
imageMirroringKey: string(imageMirrorModeJournal),
|
||||||
schedulingIntervalKey: "1h",
|
schedulingIntervalKey: "1h",
|
||||||
},
|
},
|
||||||
true,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"when startTime is specified without interval",
|
"when startTime is specified without interval",
|
||||||
@ -136,7 +138,7 @@ func TestValidateSchedulingDetails(t *testing.T) {
|
|||||||
tt := tt
|
tt := tt
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
err := validateSchedulingDetails(tt.parameters)
|
err := validateSchedulingDetails(ctx, tt.parameters)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("getSchedulingDetails() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("getSchedulingDetails() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user