Skip to content

Commit

Permalink
Merge pull request #973 from PravinRanjan10/master
Browse files Browse the repository at this point in the history
Fileshare feature: Adding capability to create fileshare from snapshots
  • Loading branch information
skdwriting committed Aug 7, 2019
2 parents 1b2e209 + d468cb0 commit a9aba69
Show file tree
Hide file tree
Showing 9 changed files with 361 additions and 36 deletions.
15 changes: 15 additions & 0 deletions contrib/drivers/filesharedrivers/nfs/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,21 @@ func (c *Cli) CreateFileShare(lvPath string) error {
return err
}

func (c *Cli) CreateFileShareFromSnapshot(lvPath string) error {
cmd := []string{
"env", "LC_ALL=C",
"lvconvert",
"--merge",
lvPath,
}
_, err := c.execute(cmd...)
if err != nil {
// Deal with the error, probably pushing it up the call stack
return err
}
return nil
}

func (c *Cli) CreateVolume(name string, vg string, size int64) error {
cmd := []string{
"env", "LC_ALL=C",
Expand Down
86 changes: 60 additions & 26 deletions contrib/drivers/filesharedrivers/nfs/nfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const (
KFileshareSnapID = "snapshotID"
AccessLevelRo = "ro"
AccessLevelRw = "rw"
MountPath = "/mnt"
)

type NFSConfig struct {
Expand Down Expand Up @@ -146,6 +147,7 @@ func (d *Driver) DeleteFileShareAcl(opt *pb.DeleteFileShareAclOpts) error {
}

func (d *Driver) CreateFileShare(opt *pb.CreateFileShareOpts) (*model.FileShareSpec, error) {

var fshare *model.FileShareSpec
//get the server ip for configuration
var server = d.conf.TgtBindIp
Expand All @@ -154,7 +156,7 @@ func (d *Driver) CreateFileShare(opt *pb.CreateFileShareOpts) (*model.FileShareS
//get volume group
var vg = opt.GetPoolName()
// Crete a directory to mount
var dirName = path.Join("/var/", name)
var dirName = path.Join(MountPath, name)
// create a fileshare path
var lvPath = path.Join("/dev", vg, name)

Expand All @@ -163,28 +165,59 @@ func (d *Driver) CreateFileShare(opt *pb.CreateFileShareOpts) (*model.FileShareS
return nil, err
}

if err := d.cli.CreateVolume(name, vg, opt.GetSize()); err != nil {
return nil, err
}
// remove created volume if got error
defer func() {
// using return value as the error flag
if fshare == nil {
if err := d.cli.Delete(name, vg); err != nil {
log.Error("failed to remove volume fileshare:", err)
}
if opt.SnapshotId != "" {
// User requested for creating fileshare using existing snapshot
//get fileshare name
var existingFsName = opt.GetMetadata()[KFileshareName]

// get existingfileshare snap logical path
//get volume group
var vg = opt.GetPoolName()
// create a fileshare device path
var lvPathForSnap = path.Join("/dev", vg, opt.SnapshotName)
// create a existing fileshare device path
var lvPathExistingPath = path.Join("/dev", vg, existingFsName)
// get directory where fileshare mounted
var olddirName = path.Join(MountPath, existingFsName)
// umount the volume to directory
if err := d.cli.UnMount(olddirName); err != nil {
log.Error("failed to unmount a directory:", err)
return nil, err
}
}()

// Crete fileshare on this path
if err := d.cli.CreateFileShare(lvPath); err != nil {
log.Error("failed to create filesystem logic volume:", err)
return nil, err
}
// mount the volume to directory
if err := d.cli.Mount(lvPath, dirName); err != nil {
log.Error("failed to mount a directory:", err)
return nil, err
if err := d.cli.CreateFileShareFromSnapshot(lvPathForSnap); err != nil {
log.Error("failed to create filesystem from given snapshot:", err)
return nil, err
}
// mount the volume to directory
if err := d.cli.Mount(lvPathExistingPath, dirName); err != nil {
log.Error("failed to mount a directory:", err)
return nil, err
}
} else {
if err := d.cli.CreateVolume(name, vg, opt.GetSize()); err != nil {
return nil, err
}
// remove created volume if got error
defer func() {
// using return value as the error flag
if fshare == nil {
if err := d.cli.Delete(name, vg); err != nil {
log.Error("failed to remove volume fileshare:", err)
}
}
}()

// Crete fileshare on this path
if err := d.cli.CreateFileShare(lvPath); err != nil {
log.Error("failed to create filesystem logic volume:", err)
return nil, err
}
// mount the volume to directory
if err := d.cli.Mount(lvPath, dirName); err != nil {
log.Error("failed to mount a directory:", err)
return nil, err
}
}
// Set permission to directory
if err := d.cli.SetPermission(dirName); err != nil {
Expand Down Expand Up @@ -212,9 +245,10 @@ func (d *Driver) CreateFileShare(opt *pb.CreateFileShareOpts) (*model.FileShareS
Protocols: []string{NFSProtocol},
ExportLocations: location,
Metadata: map[string]string{
KFileshareName: name,
KFileshareID: opt.GetId(),
KLvPath: lvPath,
KFileshareName: name,
KFileshareSnapName: "",
KFileshareID: opt.GetId(),
KLvPath: lvPath,
},
}
return fshare, nil
Expand Down Expand Up @@ -262,11 +296,11 @@ func (d *Driver) DeleteFileShare(opt *pb.DeleteFileShareOpts) error {
// get fileshare path
lvPath := opt.GetMetadata()[KLvPath]
// get directory where fileshare mounted
var dirName = path.Join("/var/", fname)
var dirName = path.Join(MountPath, fname)

// umount the volume to directory
if err := d.cli.UnMount(dirName); err != nil {
log.Error("failed to mount a directory:", err)
log.Error("failed to unmount the directory:", err)
return err
}
// delete the actual fileshare from device
Expand Down
196 changes: 196 additions & 0 deletions contrib/drivers/filesharedrivers/nfs/nfs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
// Copyright 2019 The OpenSDS Authors.
//
// 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 nfs

import (
"fmt"
"reflect"
"testing"

//"github.com/opensds/opensds/contrib/drivers/filesharedrivers/nfs"
. "github.com/opensds/opensds/contrib/drivers/utils/config"
"github.com/opensds/opensds/pkg/model"
pb "github.com/opensds/opensds/pkg/model/proto"
"github.com/opensds/opensds/pkg/utils/config"
"github.com/opensds/opensds/pkg/utils/exec"
)

var fp = map[string]PoolProperties{
"opensds-files-default": {
StorageType: "file",
AvailabilityZone: "default",
MultiAttach: true,
Extras: model.StoragePoolExtraSpec{
DataStorage: model.DataStorageLoS{
ProvisioningPolicy: "Thin",
IsSpaceEfficient: false,
StorageAccessCapability: []string{"Read", "Write", "Execute"},
},
IOConnectivity: model.IOConnectivityLoS{
AccessProtocol: "nfs",
MaxIOPS: 7000000,
MaxBWS: 600,
},
Advanced: map[string]interface{}{
"diskType": "SSD",
"latency": "5ms",
},
},
},
}

func TestSetup(t *testing.T) {
var d = &Driver{}
config.CONF.OsdsDock.Backends.NFS.ConfigPath = "testdata/nfs.yaml"
var expectedDriver = &Driver{
conf: &NFSConfig{
Pool: fp,
TgtBindIp: "11.242.178.20",
TgtConfDir: "/etc/tgt/conf.d",
EnableChapAuth: false,
},
}

if err := d.Setup(); err != nil {
t.Errorf("Setup nfs driver failed: %+v\n", err)
}
if !reflect.DeepEqual(d.conf, expectedDriver.conf) {
t.Errorf("Expected %+v, got %+v", expectedDriver.conf, d.conf)
}
}

type FakeResp struct {
out string
err error
}

func NewFakeExecuter(respMap map[string]*FakeResp) exec.Executer {
return &FakeExecuter{RespMap: respMap}
}

type FakeExecuter struct {
RespMap map[string]*FakeResp
}

func (f *FakeExecuter) Run(name string, args ...string) (string, error) {
var cmd = name
if name == "env" {
cmd = args[1]
}
v, ok := f.RespMap[cmd]
if !ok {
return "", fmt.Errorf("can not find specified op: %s", args[1])
}
return v.out, v.err
}

func TestCreateFileShare(t *testing.T) {
var fd = &Driver{}
config.CONF.OsdsDock.Backends.NFS.ConfigPath = "testdata/nfs.yaml"
fd.Setup()

respMap := map[string]*FakeResp{
"mkdir": {"", nil},
"mke2fs": {"", nil},
"mount": {"", nil},
"chmod": {"", nil},
"lvconvert": {"", nil},
"lvcreate": {"", nil},
}
fd.cli.RootExecuter = NewFakeExecuter(respMap)
fd.cli.BaseExecuter = NewFakeExecuter(respMap)

opt := &pb.CreateFileShareOpts{
Id: "e1bb066c-5ce7-46eb-9336-25508cee9f71",
Name: "test001",
Description: "fileshare for testing",
Size: int64(1),
PoolName: "vg001",
}
var expected = &model.FileShareSpec{
BaseModel: &model.BaseModel{Id: "e1bb066c-5ce7-46eb-9336-25508cee9f71"},
Name: "test001",
Description: "fileshare for testing",
Size: int64(1),
Protocols: []string{"nfs"},
ExportLocations: []string{"11.242.178.20:/var/test001"},
Metadata: map[string]string{
"lvPath": "/dev/vg001/test001",
"nfsFileshareID": "e1bb066c-5ce7-46eb-9336-25508cee9f71",
"nfsFileshareName": "test001",
"snapshotName": "",
},
}
fileshare, err := fd.CreateFileShare(opt)
if err != nil {
t.Error("Failed to create fileshare:", err)
}
if !reflect.DeepEqual(fileshare, expected) {
t.Errorf("Expected %+v, got %+v\n", expected, fileshare)
}
}

func TestListPools(t *testing.T) {
var fd = &Driver{}
config.CONF.OsdsDock.Backends.NFS.ConfigPath = "testdata/nfs.yaml"
fd.Setup()

var vgsResp = `opensds-files-default 20.00 20.00 WSpJ3r-JYVF-DYNq-1rCe-5I6j-Zb3d-8Ub0Hg
opensds-volumes-default 20.00 20.00 t7mLWW-AeCf-LtuF-7K8p-R4xA-QC5x-61qx3H`
respMap := map[string]*FakeResp{
"vgs": {vgsResp, nil},
}
fd.cli.RootExecuter = NewFakeExecuter(respMap)
fd.cli.BaseExecuter = NewFakeExecuter(respMap)

var expected = []*model.StoragePoolSpec{
{
BaseModel: &model.BaseModel{},
Name: "opensds-files-default",
TotalCapacity: int64(20),
FreeCapacity: int64(20),
AvailabilityZone: "default",
StorageType: "file",
MultiAttach: false,
Extras: model.StoragePoolExtraSpec{
DataStorage: model.DataStorageLoS{
ProvisioningPolicy: "Thin",
IsSpaceEfficient: false,
StorageAccessCapability: []string{"Read", "Write", "Execute"},
},
IOConnectivity: model.IOConnectivityLoS{
AccessProtocol: "nfs",
MaxIOPS: 7000000,
MaxBWS: 600,
},
Advanced: map[string]interface{}{
"diskType": "SSD",
"latency": "5ms",
},
},
},
}

pols, err := fd.ListPools()
if err != nil {
t.Error("Failed to list pools:", err)
}
for i := range pols {
pols[i].Id = ""
}
if !reflect.DeepEqual(pols, expected) {
t.Errorf("Expected %+v, got %+v\n", expected[0], pols[0])
}
}
23 changes: 23 additions & 0 deletions contrib/drivers/filesharedrivers/nfs/testdata/nfs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
tgtBindIp: 11.242.178.20
tgtConfDir: /etc/tgt/conf.d
pool:
opensds-files-default:
diskType: NL-SAS
availabilityZone: default
multiAttach: true
storageType: file
extras:
dataStorage:
provisioningPolicy: Thin
isSpaceEfficient: false
storageAccessCapability:
- Read
- Write
- Execute
ioConnectivity:
accessProtocol: nfs
maxIOPS: 7000000
maxBWS: 600
advanced:
diskType: SSD
latency: 5ms

0 comments on commit a9aba69

Please sign in to comment.