diff --git a/go.mod b/go.mod index 2c3475356..3ee9f3bd4 100644 --- a/go.mod +++ b/go.mod @@ -6,10 +6,10 @@ require ( github.com/RoaringBitmap/roaring v1.9.4 github.com/google/uuid v1.6.0 github.com/longhorn/backupstore v0.0.0-20240624084713-e98e31ebcebb - github.com/longhorn/go-common-libs v0.0.0-20240616051056-103c7d62a0d5 - github.com/longhorn/go-spdk-helper v0.0.0-20240616091844-5afd86a1d892 + github.com/longhorn/go-common-libs v0.0.0-20240625070844-d22ff30a7739 + github.com/longhorn/go-spdk-helper v0.0.0-20240625071858-89fcb1c09841 github.com/longhorn/longhorn-engine v1.7.0-dev.0.20240625050518-004f204f31da - github.com/longhorn/longhorn-spdk-engine v0.0.0-20240616100437-deee5f023642 + github.com/longhorn/longhorn-spdk-engine v0.0.0-20240625135632-0bfe63e91b75 github.com/longhorn/types v0.0.0-20240624083620-f11ba48bf396 github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.3 diff --git a/go.sum b/go.sum index 7bbce95fd..723377857 100644 --- a/go.sum +++ b/go.sum @@ -63,16 +63,16 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/longhorn/backupstore v0.0.0-20240624084713-e98e31ebcebb h1:equCPROzsJiPG94T4GkF78qROAIIEk107OAz3gUUJAI= github.com/longhorn/backupstore v0.0.0-20240624084713-e98e31ebcebb/go.mod h1:8+cn7oATMLHE8x8BUZ+U/HSn1odDHVbRgnsLSB43i/8= -github.com/longhorn/go-common-libs v0.0.0-20240616051056-103c7d62a0d5 h1:Ljroa7ftGJQsu38xoUlRVqZpfpkoIdrpzLM2/Qov/Vw= -github.com/longhorn/go-common-libs v0.0.0-20240616051056-103c7d62a0d5/go.mod h1:f4+Aeju9AmWPDfy7t2n0bv0Zyte8Hhs6ZhWFVf2BfWU= +github.com/longhorn/go-common-libs v0.0.0-20240625070844-d22ff30a7739 h1:KIk1RiBLBan36iOfYIrHAFG1tGSa4GyrnjMTVWHaPmY= +github.com/longhorn/go-common-libs v0.0.0-20240625070844-d22ff30a7739/go.mod h1:wpLEAlsDCnqBA7QfZg0gxYeR8MmLbWHbdidWYwnRbyM= github.com/longhorn/go-iscsi-helper v0.0.0-20240513041205-7a18d2fd85bf h1:J3VeBJa5XBm6n/U7TEi0dqYIECzBVJndZBV6yoOpP+g= github.com/longhorn/go-iscsi-helper v0.0.0-20240513041205-7a18d2fd85bf/go.mod h1:J7J4FcOvgk+bCB/O85uJU1IJMRrsT42H5icJcvaQgC8= -github.com/longhorn/go-spdk-helper v0.0.0-20240616091844-5afd86a1d892 h1:ph1ZasNZQnztQvUNdTmBpx7GzMx6b5eth07WwO3vVUU= -github.com/longhorn/go-spdk-helper v0.0.0-20240616091844-5afd86a1d892/go.mod h1:dUMQPK0GsY+sX8MEvKR5Yb53uRDErEqMTTKPw26d3go= +github.com/longhorn/go-spdk-helper v0.0.0-20240625071858-89fcb1c09841 h1:AE/vFD8LhXjqB4mOkce/nAUmF8ry04YAxYd3kozBy5I= +github.com/longhorn/go-spdk-helper v0.0.0-20240625071858-89fcb1c09841/go.mod h1:ZlEVr1x/veZpGRD2+6x0goA/6Zol9+is6AJ2/5eAIuw= github.com/longhorn/longhorn-engine v1.7.0-dev.0.20240625050518-004f204f31da h1:2q0y1pHlZzCUBbGGeiQmYt/T1tGzrWzCHRiCuJS63LI= github.com/longhorn/longhorn-engine v1.7.0-dev.0.20240625050518-004f204f31da/go.mod h1:BMCPI+P2NadsubCOWtmv1bOutScmDVOsoOfu/dXles4= -github.com/longhorn/longhorn-spdk-engine v0.0.0-20240616100437-deee5f023642 h1:Ph5daSeSXJSUYWvVa3OTRIoWq1u0N39URoKUlBhIFtM= -github.com/longhorn/longhorn-spdk-engine v0.0.0-20240616100437-deee5f023642/go.mod h1:12Knt1EO/pCWUcrwGmtGre83nURPw4tUPxepquF51qI= +github.com/longhorn/longhorn-spdk-engine v0.0.0-20240625135632-0bfe63e91b75 h1:h/38PoazDjwzZ/wdKQG4NK8EL91p6UxN+q/aaJaj8bE= +github.com/longhorn/longhorn-spdk-engine v0.0.0-20240625135632-0bfe63e91b75/go.mod h1:d0mJeEEZ/EPGFBK01AkAlWNVSjTWd9Bweja08MX4UYo= github.com/longhorn/nsfilelock v0.0.0-20200723175406-fa7c83ad0003 h1:Jw9uANsGcHTxp6HcC++/vN17LfeuDmozHI2j6DoZf5E= github.com/longhorn/nsfilelock v0.0.0-20200723175406-fa7c83ad0003/go.mod h1:0CLeXlf59Lg6C0kjLSDf47ft73Dh37CwymYRKWwAn04= github.com/longhorn/sparse-tools v0.0.0-20240513025352-ed49dd3f93eb h1:Kh89s6i5T1W6BT1Aq9W1YHXojbbcTXlDieWC5KWAs/E= diff --git a/vendor/github.com/longhorn/go-common-libs/io/file.go b/vendor/github.com/longhorn/go-common-libs/io/file.go index 945be4d78..9bd9d4cc7 100644 --- a/vendor/github.com/longhorn/go-common-libs/io/file.go +++ b/vendor/github.com/longhorn/go-common-libs/io/file.go @@ -5,6 +5,7 @@ import ( "io" "os" "path/filepath" + "strings" "syscall" "time" @@ -164,12 +165,29 @@ func GetEmptyFiles(directory string) (filePaths []string, err error) { // FindFiles searches for files in the specified directory with the given fileName. // If fileName is empty, it retrieves all files in the directory. +// If maxDepth is greater than 0, it limits the search to the specified depth. // It returns a slice of filePaths and an error if any. -func FindFiles(directory, fileName string) (filePaths []string, err error) { +func FindFiles(directory, fileName string, maxDepth int) (filePaths []string, err error) { err = filepath.Walk(directory, func(path string, info os.FileInfo, err error) error { if err != nil { - return err + // If the directory contains symbolic links, it might lead to a non-existing file error. + // Ignore this error and continue walking the directory. + logrus.WithError(err).Warn("Encountered error while searching for files") + return nil + } + + // Calculate the depth of the directory + depth := strings.Count(strings.TrimPrefix(path, directory), string(os.PathSeparator)) + + // Skip the directory if it exceeds the maximum depth + if maxDepth > 0 && depth > maxDepth { + if info.IsDir() { + return filepath.SkipDir // Skip this directory + } + + return nil // Skip this file } + if fileName == "" || info.Name() == fileName { filePaths = append(filePaths, path) } @@ -241,3 +259,103 @@ func GetDiskStat(path string) (diskStat types.DiskStat, err error) { StorageAvailable: int64(statfs.Bfree) * statfs.Bsize, }, nil } + +// ListOpenFiles returns a list of open files in the specified directory. +func ListOpenFiles(procDirectory, directory string) ([]string, error) { + // Check if the specified directory exists + if _, err := os.Stat(directory); err != nil { + return nil, err + } + + // Get the list of all processes in the provided procDirectory + procs, err := os.ReadDir(procDirectory) + if err != nil { + return nil, err + } + + // Iterate over each process in the procDirectory + var openedFiles []string + for _, proc := range procs { + // Skip non-directory entries + if !proc.IsDir() { + continue + } + + // Read the file descriptor directory for the process + pid := proc.Name() + fdDir := filepath.Join(procDirectory, pid, "fd") + files, err := os.ReadDir(fdDir) + if err != nil { + logrus.WithError(err).Tracef("Failed to read file descriptors for process %v", pid) + continue + } + + // Iterate over each file in the file descriptor directory + for _, file := range files { + filePath, err := os.Readlink(filepath.Join(fdDir, file.Name())) + if err != nil { + logrus.WithError(err).Tracef("Failed to read link for file descriptor %v", file.Name()) + continue + } + + // Check if the file path is within the specified directory + if strings.HasPrefix(filePath, directory+"/") || filePath == directory { + openedFiles = append(openedFiles, filePath) + } + } + } + + return openedFiles, nil +} + +// IsDirectoryEmpty returns true if the specified directory is empty. +func IsDirectoryEmpty(directory string) (bool, error) { + f, err := os.Open(directory) + if err != nil { + return false, err + } + defer f.Close() + + _, err = f.Readdirnames(1) + if err == io.EOF { + return true, nil + } + if err != nil { + return false, err + } + + return false, nil +} + +// CheckIsFileSizeSame verifies if all files in the provided paths have the same size. +// It returns an error if any file is a directory, does not exist, or has a different size. +func CheckIsFileSizeSame(paths ...string) error { + referenceInfo, err := os.Stat(paths[0]) + if err != nil { + return err + } + + if referenceInfo.IsDir() { + return errors.Errorf("file %v is a directory", paths[0]) + } + + referenceSize := referenceInfo.Size() + + for _, path := range paths { + fileInfo, err := os.Stat(path) + if err != nil { + return err + } + + if fileInfo.IsDir() { + return errors.Errorf("file %v is a directory", path) + + } + + if fileInfo.Size() != referenceSize { + return errors.Errorf("file %v size %v is not equal to %v", path, fileInfo.Size(), referenceSize) + } + } + + return nil +} diff --git a/vendor/github.com/longhorn/go-common-libs/utils/longhorn_naming.go b/vendor/github.com/longhorn/go-common-libs/utils/longhorn_naming.go deleted file mode 100644 index 5db2d4b4d..000000000 --- a/vendor/github.com/longhorn/go-common-libs/utils/longhorn_naming.go +++ /dev/null @@ -1,11 +0,0 @@ -package utils - -import ( - "regexp" -) - -// IsEngineProcess distinguish if the process is a engine process by its name. -func IsEngineProcess(processName string) bool { - // engine process name example: pvc-5a8ee916-5989-46c6-bafc-ddbf7c802499-e-0 - return regexp.MustCompile(`.+?-e-[^-]*\d$`).MatchString(processName) -} diff --git a/vendor/github.com/longhorn/go-common-libs/utils/misc.go b/vendor/github.com/longhorn/go-common-libs/utils/misc.go index 8485c6797..69aced9ce 100644 --- a/vendor/github.com/longhorn/go-common-libs/utils/misc.go +++ b/vendor/github.com/longhorn/go-common-libs/utils/misc.go @@ -2,10 +2,12 @@ package utils import ( "crypto/rand" + "fmt" "math/big" "path/filepath" "reflect" "runtime" + "strconv" "strings" "github.com/google/uuid" @@ -99,3 +101,21 @@ func GenerateRandomNumber(lower, upper int64) (int64, error) { } return (lower + randNum.Int64()), nil } + +// ConvertTypeToString converts the given value to string. +func ConvertTypeToString[T any](value T) string { + v := reflect.ValueOf(value) + + switch v.Kind() { + case reflect.String: + return v.String() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return strconv.FormatInt(v.Int(), 10) + case reflect.Float32, reflect.Float64: + return strconv.FormatFloat(v.Float(), 'f', -1, 64) + case reflect.Bool: + return strconv.FormatBool(v.Bool()) + default: + return fmt.Sprintf("Unsupported type: %v", v.Kind()) + } +} diff --git a/vendor/github.com/longhorn/go-common-libs/utils/mount.go b/vendor/github.com/longhorn/go-common-libs/utils/mount.go deleted file mode 100644 index f234ae1a3..000000000 --- a/vendor/github.com/longhorn/go-common-libs/utils/mount.go +++ /dev/null @@ -1,14 +0,0 @@ -package utils - -import ( - "k8s.io/mount-utils" -) - -func IsMountPointReadOnly(mp mount.MountPoint) bool { - for _, opt := range mp.Opts { - if opt == "ro" { - return true - } - } - return false -} diff --git a/vendor/github.com/longhorn/go-spdk-helper/pkg/spdk/client/basic.go b/vendor/github.com/longhorn/go-spdk-helper/pkg/spdk/client/basic.go index 6972de36a..701bf0794 100644 --- a/vendor/github.com/longhorn/go-spdk-helper/pkg/spdk/client/basic.go +++ b/vendor/github.com/longhorn/go-spdk-helper/pkg/spdk/client/basic.go @@ -365,24 +365,52 @@ func (c *Client) BdevLvolResize(name string, size uint64) (resized bool, err err return resized, json.Unmarshal(cmdOutput, &resized) } -// BdevLvolShallowCopy make a shallow copy of lvol over a given bdev. +// BdevLvolStartShallowCopy start a shallow copy of lvol over a given bdev. // Only clusters allocated to the lvol will be written on the bdev. +// Returns the operation ID needed to check the shallow copy status with BdevLvolCheckShallowCopy. // // "srcLvolName": Required. UUID or alias of lvol to create a copy from. // // "dstBdevName": Required. Name of the bdev that acts as destination for the copy. -func (c *Client) BdevLvolShallowCopy(srcLvolName, dstBdevName string) (copied bool, err error) { +func (c *Client) BdevLvolStartShallowCopy(srcLvolName, dstBdevName string) (operationId uint32, err error) { req := spdktypes.BdevLvolShallowCopyRequest{ SrcLvolName: srcLvolName, DstBdevName: dstBdevName, } - cmdOutput, err := c.jsonCli.SendCommandWithLongTimeout("bdev_lvol_shallow_copy", req) + cmdOutput, err := c.jsonCli.SendCommand("bdev_lvol_start_shallow_copy", req) if err != nil { - return false, err + return 0, err + } + + shallowCopy := spdktypes.ShallowCopy{} + err = json.Unmarshal(cmdOutput, &shallowCopy) + if err != nil { + return 0, err + } + + return shallowCopy.OperationId, nil +} + +// BdevLvolCheckShallowCopy check the status of a shallow copy previously started. +// +// "operationId": Required. Operation ID of the shallow copy to check. +func (c *Client) BdevLvolCheckShallowCopy(operationId uint32) (*spdktypes.ShallowCopyStatus, error) { + shallowCopy := spdktypes.ShallowCopy{ + OperationId: operationId, + } + cmdOutput, err := c.jsonCli.SendCommand("bdev_lvol_check_shallow_copy", shallowCopy) + if err != nil { + return nil, err + } + + var shallowCopyStatus spdktypes.ShallowCopyStatus + err = json.Unmarshal(cmdOutput, &shallowCopyStatus) + if err != nil { + return nil, err } - return copied, json.Unmarshal(cmdOutput, &copied) + return &shallowCopyStatus, nil } // BdevLvolGetFragmap gets fragmap of the specific segment of the logical volume. diff --git a/vendor/github.com/longhorn/go-spdk-helper/pkg/spdk/types/lvol.go b/vendor/github.com/longhorn/go-spdk-helper/pkg/spdk/types/lvol.go index 74735a5e0..6ff8b9e2f 100644 --- a/vendor/github.com/longhorn/go-spdk-helper/pkg/spdk/types/lvol.go +++ b/vendor/github.com/longhorn/go-spdk-helper/pkg/spdk/types/lvol.go @@ -42,6 +42,17 @@ type LvolInfo struct { } `json:"lvs"` } +type ShallowCopy struct { + OperationId uint32 `json:"operation_id"` +} + +type ShallowCopyStatus struct { + State string `json:"state"` + CopiedClusters uint64 `json:"copied_clusters"` + TotalClusters uint64 `json:"total_clusters"` + Error string `json:"error,omitempty"` +} + type BdevLvolCreateLvstoreRequest struct { BdevName string `json:"bdev_name"` LvsName string `json:"lvs_name"` diff --git a/vendor/github.com/longhorn/longhorn-spdk-engine/pkg/spdk/engine.go b/vendor/github.com/longhorn/longhorn-spdk-engine/pkg/spdk/engine.go index 26898eb6c..54ac96938 100644 --- a/vendor/github.com/longhorn/longhorn-spdk-engine/pkg/spdk/engine.go +++ b/vendor/github.com/longhorn/longhorn-spdk-engine/pkg/spdk/engine.go @@ -140,7 +140,7 @@ func (e *Engine) Create(spdkClient *spdkclient.Client, replicaAddressMap map[str replicaBdevList := []string{} for replicaName, replicaAddr := range replicaAddressMap { - bdevName, err := e.getBdevNameForReplica(spdkClient, replicaName, replicaAddr, podIP) + bdevName, err := e.connectReplica(spdkClient, replicaName, replicaAddr) if err != nil { e.log.WithError(err).Errorf("Failed to get bdev from replica %s with address %s, will skip it and continue", replicaName, replicaAddr) e.ReplicaModeMap[replicaName] = types.ModeERR @@ -174,10 +174,6 @@ func (e *Engine) Create(spdkClient *spdkclient.Client, replicaAddressMap map[str return e.getWithoutLock(), nil } -func (e *Engine) getBdevNameForReplica(spdkClient *spdkclient.Client, replicaName, replicaAddress, podIP string) (bdevName string, err error) { - return e.connectReplica(spdkClient, replicaName, replicaAddress) -} - func (e *Engine) connectReplica(spdkClient *spdkclient.Client, replicaName, replicaAddress string) (bdevName string, err error) { replicaIP, replicaPort, err := net.SplitHostPort(replicaAddress) if err != nil { @@ -825,7 +821,7 @@ func (e *Engine) ReplicaAddFinish(spdkClient *spdkclient.Client, replicaName, re replicaBdevList = append(replicaBdevList, e.ReplicaBdevNameMap[rName]) } if rName == replicaName { - bdevName, err := e.getBdevNameForReplica(spdkClient, replicaName, replicaAddress, e.IP) + bdevName, err := e.connectReplica(spdkClient, replicaName, replicaAddress) if err != nil { e.log.WithError(err).Errorf("Failed to get bdev from rebuilding replica %s with address %s, will mark it as ERR and error out", replicaName, replicaAddress) e.ReplicaModeMap[replicaName] = types.ModeERR @@ -1065,10 +1061,14 @@ const ( SnapshotOperationRevert = SnapshotOperationType("snapshot-revert") ) -func (e *Engine) SnapshotCreate(spdkClient *spdkclient.Client, inputSnapshotName string, opts *api.SnapshotOptions) (snapshotName string, err error) { +func (e *Engine) SnapshotCreate(spdkClient *spdkclient.Client, inputSnapshotName string) (snapshotName string, err error) { e.log.Infof("Creating snapshot %s", inputSnapshotName) - return e.snapshotOperation(spdkClient, inputSnapshotName, SnapshotOperationCreate, opts) + opts := api.SnapshotOptions{ + UserCreated: true, + } + + return e.snapshotOperation(spdkClient, inputSnapshotName, SnapshotOperationCreate, &opts) } func (e *Engine) SnapshotDelete(spdkClient *spdkclient.Client, snapshotName string) (err error) { diff --git a/vendor/github.com/longhorn/longhorn-spdk-engine/pkg/spdk/server.go b/vendor/github.com/longhorn/longhorn-spdk-engine/pkg/spdk/server.go index 1f70e8f31..06ae6ce51 100644 --- a/vendor/github.com/longhorn/longhorn-spdk-engine/pkg/spdk/server.go +++ b/vendor/github.com/longhorn/longhorn-spdk-engine/pkg/spdk/server.go @@ -893,11 +893,7 @@ func (s *Server) EngineSnapshotCreate(ctx context.Context, req *spdkrpc.Snapshot return nil, grpcstatus.Errorf(grpccodes.NotFound, "cannot find engine %v for snapshot creation", req.Name) } - opts := api.SnapshotOptions{ - UserCreated: req.UserCreated, - } - - snapshotName, err := e.SnapshotCreate(spdkClient, req.SnapshotName, &opts) + snapshotName, err := e.SnapshotCreate(spdkClient, req.SnapshotName) return &spdkrpc.SnapshotResponse{SnapshotName: snapshotName}, err } diff --git a/vendor/modules.txt b/vendor/modules.txt index 1854fdbfc..100aec853 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -142,7 +142,7 @@ github.com/longhorn/backupstore/s3 github.com/longhorn/backupstore/types github.com/longhorn/backupstore/util github.com/longhorn/backupstore/vfs -# github.com/longhorn/go-common-libs v0.0.0-20240616051056-103c7d62a0d5 +# github.com/longhorn/go-common-libs v0.0.0-20240625070844-d22ff30a7739 ## explicit; go 1.22.0 github.com/longhorn/go-common-libs/backup github.com/longhorn/go-common-libs/exec @@ -161,7 +161,7 @@ github.com/longhorn/go-iscsi-helper/iscsidev github.com/longhorn/go-iscsi-helper/longhorndev github.com/longhorn/go-iscsi-helper/types github.com/longhorn/go-iscsi-helper/util -# github.com/longhorn/go-spdk-helper v0.0.0-20240616091844-5afd86a1d892 +# github.com/longhorn/go-spdk-helper v0.0.0-20240625071858-89fcb1c09841 ## explicit; go 1.22.0 github.com/longhorn/go-spdk-helper/pkg/jsonrpc github.com/longhorn/go-spdk-helper/pkg/nvme @@ -183,7 +183,7 @@ github.com/longhorn/longhorn-engine/pkg/sync github.com/longhorn/longhorn-engine/pkg/types github.com/longhorn/longhorn-engine/pkg/util github.com/longhorn/longhorn-engine/pkg/util/disk -# github.com/longhorn/longhorn-spdk-engine v0.0.0-20240616100437-deee5f023642 +# github.com/longhorn/longhorn-spdk-engine v0.0.0-20240625135632-0bfe63e91b75 ## explicit; go 1.22.0 github.com/longhorn/longhorn-spdk-engine/pkg/api github.com/longhorn/longhorn-spdk-engine/pkg/client