Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block Metro volume from Metro PV or Snapshot #378

Merged
merged 21 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .mockery.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
#
#

quiet: False
all: True
inpackage: False
quiet: false
all: true
inpackage: false
dir: ./pkg
disable-version-string: True
disable-version-string: true
4 changes: 2 additions & 2 deletions pkg/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,10 @@ const (
SyncMode = "SYNC"
// AsyncMode indicats Asynchronous Replication
AsyncMode = "ASYNC"
// MetroMode indicates Metro Replication
MetroMode = "METRO"
// Zero indicates value zero for RPO
Zero = "Zero"
// Metro indicates Metro mode
Metro = "METRO"

contextLogFieldsKey key = iota

Expand Down
69 changes: 68 additions & 1 deletion pkg/common/common_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright © 2021-2023 Dell Inc. or its subsidiaries. All Rights Reserved.
* Copyright © 2021-2024 Dell Inc. or its subsidiaries. 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.
Expand Down Expand Up @@ -35,6 +35,7 @@ import (
gopowerstoremock "github.com/dell/gopowerstore/mocks"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)

func TestCustomLogger(_ *testing.T) {
Expand Down Expand Up @@ -116,6 +117,20 @@ func TestGetISCSITargetsInfoFromStorage(t *testing.T) {
_, err := common.GetISCSITargetsInfoFromStorage(clientMock, "A1")
assert.EqualError(t, err, e.Error())
})

t.Run("no error", func(t *testing.T) {
clientMock := new(gopowerstoremock.Client)
clientMock.On("GetStorageISCSITargetAddresses", context.Background()).
Return([]gopowerstore.IPPoolAddress{
{
Address: "192.168.1.1",
IPPort: gopowerstore.IPPortInstance{TargetIqn: "iqn"},
},
}, nil)
iscsiTargetsInfo, err := common.GetISCSITargetsInfoFromStorage(clientMock, "")
assert.NotNil(t, iscsiTargetsInfo)
assert.NoError(t, err)
})
}

func TestGetNVMETCPTargetsInfoFromStorage(t *testing.T) {
Expand All @@ -127,6 +142,21 @@ func TestGetNVMETCPTargetsInfoFromStorage(t *testing.T) {
_, err := common.GetNVMETCPTargetsInfoFromStorage(clientMock, "A1")
assert.EqualError(t, err, e.Error())
})

t.Run("no error", func(t *testing.T) {
clientMock := new(gopowerstoremock.Client)
clientMock.On("GetCluster", context.Background()).Return(gopowerstore.Cluster{}, nil)
clientMock.On("GetStorageNVMETCPTargetAddresses", mock.Anything).
Return([]gopowerstore.IPPoolAddress{
{
Address: "192.168.1.1",
IPPort: gopowerstore.IPPortInstance{TargetIqn: "iqn"},
},
}, nil)
nvmetcpTargetInfo, err := common.GetNVMETCPTargetsInfoFromStorage(clientMock, "")
assert.NotNil(t, nvmetcpTargetInfo)
assert.NoError(t, err)
})
}

func TestGetFCTargetsInfoFromStorage(t *testing.T) {
Expand All @@ -137,6 +167,21 @@ func TestGetFCTargetsInfoFromStorage(t *testing.T) {
_, err := common.GetFCTargetsInfoFromStorage(clientMock, "A1")
assert.EqualError(t, err, e.Error())
})

t.Run("no error", func(t *testing.T) {
clientMock := new(gopowerstoremock.Client)
clientMock.On("GetFCPorts", mock.Anything).
Return([]gopowerstore.FcPort{
{
Wwn: "58:cc:f0:93:48:a0:03:a3",
ApplianceID: "A1",
IsLinkUp: true,
},
}, nil)
fcTargetInfo, err := common.GetFCTargetsInfoFromStorage(clientMock, "A1")
assert.NotNil(t, fcTargetInfo)
assert.NoError(t, err)
})
}

func TestIsK8sMetadataSupported(t *testing.T) {
Expand All @@ -147,6 +192,13 @@ func TestIsK8sMetadataSupported(t *testing.T) {
version := common.IsK8sMetadataSupported(clientMock)
assert.Equal(t, version, false)
})

t.Run("no error", func(t *testing.T) {
clientMock := new(gopowerstoremock.Client)
clientMock.On("GetSoftwareMajorMinorVersion", context.Background()).Return(float32(3.0), nil)
version := common.IsK8sMetadataSupported(clientMock)
assert.Equal(t, version, true)
})
}

func TestGetNVMEFCTargetInfoFromStorage(t *testing.T) {
Expand All @@ -158,6 +210,21 @@ func TestGetNVMEFCTargetInfoFromStorage(t *testing.T) {
_, err := common.GetNVMEFCTargetInfoFromStorage(clientMock, "A1")
assert.EqualError(t, err, e.Error())
})

t.Run("no error", func(t *testing.T) {
clientMock := new(gopowerstoremock.Client)
clientMock.On("GetCluster", context.Background()).Return(gopowerstore.Cluster{}, nil)
clientMock.On("GetFCPorts", mock.Anything).
Return([]gopowerstore.FcPort{
{
Wwn: "58:cc:f0:93:48:a0:03:a3",
IsLinkUp: true,
},
}, nil)
nvmefcTargetInfo, err := common.GetNVMEFCTargetInfoFromStorage(clientMock, "")
assert.NotNil(t, nvmefcTargetInfo)
assert.NoError(t, err)
})
}

func TestHasRequiredTopology(t *testing.T) {
Expand Down
41 changes: 40 additions & 1 deletion pkg/common/fs/fs_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright © 2021 Dell Inc. or its subsidiaries. All Rights Reserved.
* Copyright © 2021-2024 Dell Inc. or its subsidiaries. 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.
Expand All @@ -19,7 +19,9 @@
package fs

import (
"context"
"os"
"strings"
"testing"

"github.com/dell/gofsutil"
Expand Down Expand Up @@ -82,6 +84,17 @@ func (suite *FsTestSuite) TestWriteFile() {
suite.Assert().Equal(bytes, data)
}

func (suite *FsTestSuite) TestOpenFile() {
file, err := suite.fs.OpenFile(suite.tmp+"/file", os.O_CREATE, 0o600)
suite.Assert().NoError(err)

err = suite.fs.Chmod(suite.tmp+"/file", os.ModeSticky)
suite.Assert().NoError(err)

err = file.Close()
suite.Assert().NoError(err)
}

func (suite *FsTestSuite) TestMkDir() {
err := suite.fs.Mkdir(suite.tmp+"/dir", 0o750)
suite.Assert().NoError(err)
Expand Down Expand Up @@ -121,6 +134,32 @@ func (suite *FsTestSuite) TestExecCommand() {
suite.Assert().NotEmpty(out)
}

func (suite *FsTestSuite) TestIsDeviceOrResourceBusy() {
err := suite.fs.Remove(suite.tmp + "/busy")
res := suite.fs.IsDeviceOrResourceBusy(err)
suite.Assert().False(res)
}

func (suite *FsTestSuite) TestParseProcMounts() {
input := `17 60 0:16 / /sys rw,nosuid,nodev,noexec,relatime shared:6 - sysfs sysfs rw,seclabel
18 60 0:3 / /proc rw,nosuid,nodev,noexec,relatime shared:5 - proc proc rw
19 60 0:5 / /dev rw,nosuid shared:2 - devtmpfs devtmpfs rw,seclabel,size=1930460k,nr_inodes=482615,mode=755
20 17 0:15 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime shared:7 - securityfs securityfs rw
21 19 0:17 / /dev/shm rw,nosuid,nodev shared:3 - tmpfs tmpfs rw,seclabel
22 19 0:11 / /dev/pts rw,nosuid,noexec,relatime shared:4 - devpts devpts rw,seclabel,gid=5,mode=620,ptmxmode=000
23 60 0:18 / /run rw,nosuid,nodev shared:23 - tmpfs tmpfs rw,seclabel,mode=755
24 17 0:19 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:8 - tmpfs tmpfs ro,seclabel,mode=755`
mounts, err := suite.fs.ParseProcMounts(context.Background(), strings.NewReader(input))
suite.Assert().NoError(err)
suite.Assert().NotEmpty(mounts)
}

func (suite *FsTestSuite) TestNetDial() {
conn, err := suite.fs.NetDial("localhost")
suite.Assert().NoError(err)
conn.Close()
}

func (suite *FsTestSuite) TestGetUtil() {
util := suite.fs.GetUtil()
suite.Assert().NotNil(util)
Expand Down
29 changes: 18 additions & 11 deletions pkg/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,26 @@ func (s *Service) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest
return nil, err
}

replicationEnabled := params[s.WithRP(KeyReplicationEnabled)]
repMode := params[s.WithRP(KeyReplicationMode)]
// Default to ASYNC for backward compatibility
if repMode == "" {
repMode = common.AsyncMode
}
repMode = strings.ToUpper(repMode)

contentSource := req.GetVolumeContentSource()
if contentSource != nil {
var volResp *csi.Volume
var err error
// Configuring Metro is not allowed on clones or volumes created from Metro snapshot.
// So, fail the request if the requested volume is to be placed in Metro storage class.
// However, one can place the volume in a non-Metro storage class.
if replicationEnabled == "true" && repMode == common.MetroMode {
return nil, status.Errorf(codes.InvalidArgument,
"Configuring Metro is not supported on clones or volumes created from Metro snapshot. Choose a non-Metro storage class.")
}

volumeSource := contentSource.GetVolume()
if volumeSource != nil {
log.Printf("volume %s specified as volume content source", volumeSource.VolumeId)
Expand Down Expand Up @@ -247,12 +263,9 @@ func (s *Service) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest

var vg gopowerstore.VolumeGroup
var remoteSystem gopowerstore.RemoteSystem

// Check if replication is enabled
replicationEnabled := params[s.WithRP(KeyReplicationEnabled)]
var remoteSystemName string
isMetroVolume := false

// Check if replication is enabled
if replicationEnabled == "true" {
if useNFS {
return nil, status.Error(codes.InvalidArgument, "replication not supported for NFS")
Expand All @@ -264,12 +277,6 @@ func (s *Service) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest
if !ok {
return nil, status.Error(codes.InvalidArgument, "replication enabled but no remote system specified in storage class")
}
repMode := params[s.WithRP(KeyReplicationMode)]
// Default to ASYNC for backward compatibility
if repMode == "" {
repMode = common.AsyncMode
}
repMode = strings.ToUpper(repMode)

switch repMode {
case common.SyncMode, common.AsyncMode:
Expand Down Expand Up @@ -369,7 +376,7 @@ func (s *Service) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest
if c, ok := creator.(*SCSICreator); ok {
c.vg = &vg
}
case common.Metro:
case common.MetroMode:
// handle Metro mode where metro is configured directly on the volume
// Note: Metro on volume group support is not added
log.Info("Metro replication mode requested")
Expand Down
Loading
Loading