diff --git a/.travis.yml b/.travis.yml index 0337b8b7a..5c5328699 100755 --- a/.travis.yml +++ b/.travis.yml @@ -2,9 +2,6 @@ dist: trusty sudo: required group: deprecated-2017Q4 -services: - - docker - language: go go_import_path: github.com/opensds/opensds @@ -44,7 +41,6 @@ install: - go get github.com/mattn/goveralls - go get github.com/wadey/gocovmerge - make - - sudo ./test/integration/prepare.sh script: - ./script/CI/coverage diff --git a/client/volume.go b/client/volume.go index 33689b1aa..4c3b4b7d7 100755 --- a/client/volume.go +++ b/client/volume.go @@ -26,6 +26,11 @@ import ( // could be discussed if it's better to define an interface. type VolumeBuilder *model.VolumeSpec +// ExtendVolumeBuilder contains request body of handling a extend volume request. +// Currently it's assigned as the pointer of ExtendVolumeSpec struct, but it +// could be discussed if it's better to define an interface. +type ExtendVolumeBuilder *model.ExtendVolumeSpec + // VolumeAttachmentBuilder contains request body of handling a volume request. // Currently it's assigned as the pointer of VolumeSpec struct, but it // could be discussed if it's better to define an interface. @@ -116,6 +121,20 @@ func (v *VolumeMgr) UpdateVolume(volID string, body VolumeBuilder) (*model.Volum return &res, nil } +// ExtendVolume ... +func (v *VolumeMgr) ExtendVolume(volID string, body ExtendVolumeBuilder) (*model.VolumeSpec, error) { + var res model.VolumeSpec + url := strings.Join([]string{ + v.Endpoint, + urls.GenerateNewVolumeURL(volID + "/action")}, "/") + + if err := v.Recv(request, url, "POST", body, &res); err != nil { + return nil, err + } + + return &res, nil +} + // CreateVolumeAttachment func (v *VolumeMgr) CreateVolumeAttachment(body VolumeAttachmentBuilder) (*model.VolumeAttachmentSpec, error) { var res model.VolumeAttachmentSpec diff --git a/client/volume_test.go b/client/volume_test.go index ea1183e77..c89e19523 100755 --- a/client/volume_test.go +++ b/client/volume_test.go @@ -227,6 +227,36 @@ func TestUpdateVolume(t *testing.T) { } } +func TestExtendVolume(t *testing.T) { + var volID = "bd5b12a8-a101-11e7-941e-d77981b584d8" + body := model.ExtendVolumeSpec{ + Extend: model.ExtendSpec{NewSize: 1}, + } + + result, err := fv.ExtendVolume(volID, &body) + if err != nil { + t.Error(err) + return + } + + expected := &model.VolumeSpec{ + BaseModel: &model.BaseModel{ + Id: "bd5b12a8-a101-11e7-941e-d77981b584d8", + }, + Name: "sample-volume", + Description: "This is a sample volume for testing", + Size: int64(1), + Status: "available", + PoolId: "084bf71e-a102-11e7-88a8-e31fe6d52248", + ProfileId: "1106b972-66ef-11e7-b172-db03f3689c9c", + } + + if !reflect.DeepEqual(result, expected) { + t.Errorf("Expected %v, got %v", expected, result) + return + } +} + func TestCreateVolumeAttachment(t *testing.T) { var volID = "bd5b12a8-a101-11e7-941e-d77981b584d8" expected := &model.VolumeAttachmentSpec{ diff --git a/contrib/drivers/ceph/ceph.go b/contrib/drivers/ceph/ceph.go index 135e19cc5..7f65070da 100755 --- a/contrib/drivers/ceph/ceph.go +++ b/contrib/drivers/ceph/ceph.go @@ -192,6 +192,44 @@ func (d *Driver) CreateVolume(opt *pb.CreateVolumeOpts) (*model.VolumeSpec, erro }, nil } +// ExtendVolume ... +func (d *Driver) ExtendVolume(opt *pb.ExtendVolumeOpts) (*model.VolumeSpec, error) { + if err := d.initConn(); err != nil { + log.Error("Connect ceph failed.") + return nil, err + } + defer d.destroyConn() + + img, _, err := d.getImage(opt.GetId()) + if err != nil { + log.Error("When get image:", err) + return nil, err + } + + if err = img.Open(); err != nil { + log.Error("When open image:", err) + return nil, err + } + defer img.Close() + + size := opt.GetSize() + if err = img.Resize(uint64(size) << sizeShiftBit); err != nil { + log.Error("When resize image:", err) + return nil, err + } + log.Info("Resize image success, volume id =", opt.GetId()) + + return &model.VolumeSpec{ + BaseModel: &model.BaseModel{ + Id: opt.GetId(), + }, + Name: opt.GetName(), + Size: size, + Description: opt.GetDescription(), + AvailabilityZone: opt.GetAvailabilityZone(), + }, nil +} + func (d *Driver) getImage(volID string) (*rbd.Image, *Name, error) { imgNames, err := rbd.GetImageNames(d.ioctx) if err != nil { diff --git a/contrib/drivers/ceph/ceph_test.go b/contrib/drivers/ceph/ceph_test.go index 1a994ff84..a8c6a61c0 100755 --- a/contrib/drivers/ceph/ceph_test.go +++ b/contrib/drivers/ceph/ceph_test.go @@ -150,6 +150,44 @@ func TestDeleteVolme(t *testing.T) { } } +func TestExtendVolume(t *testing.T) { + defer monkey.UnpatchAll() + monkey.Patch((*Driver).initConn, func(d *Driver) error { + return nil + }) + monkey.Patch(rbd.GetImageNames, func(ioctx *rados.IOContext) (names []string, err error) { + nameList := []string{opensdsPrefix + ":volume001:7ee11866-1f40-4f3c-b093-7a3684523a19"} + return nameList, nil + }) + + monkey.Patch((*rbd.Image).GetSize, func(r *rbd.Image) (size uint64, err error) { + return 1 << sizeShiftBit, nil + }) + monkey.Patch((*rbd.Image).Remove, func(r *rbd.Image) error { + return nil + }) + monkey.Patch((*rados.Conn).Shutdown, func(c *rados.Conn) {}) + monkey.Patch((*rados.IOContext).Destroy, func(ioctx *rados.IOContext) {}) + monkey.Patch((*rbd.Image).Resize, func(r *rbd.Image, size uint64) error { + return nil + }) + monkey.Patch((*rbd.Image).Open, func(r *rbd.Image, args ...interface{}) error { + return nil + }) + + d := Driver{} + opt := &pb.ExtendVolumeOpts{Name: "volume001", Id: "7ee11866-1f40-4f3c-b093-7a3684523a19", Size: 123} + resp, err := d.ExtendVolume(opt) + + if err != nil { + t.Errorf("Test Extend volume error") + } + + if resp.Size != 123 { + t.Errorf("Test Extend volume size error") + } +} + func TestCreateSnapshot(t *testing.T) { defer monkey.UnpatchAll() monkey.Patch((*Driver).initConn, func(d *Driver) error { diff --git a/contrib/drivers/drivers.go b/contrib/drivers/drivers.go index 929e425ad..b24c82449 100755 --- a/contrib/drivers/drivers.go +++ b/contrib/drivers/drivers.go @@ -45,6 +45,8 @@ type VolumeDriver interface { DeleteVolume(opt *pb.DeleteVolumeOpts) error + ExtendVolume(opt *pb.ExtendVolumeOpts) (*model.VolumeSpec, error) + InitializeConnection(opt *pb.CreateAttachmentOpts) (*model.ConnectionInfo, error) TerminateConnection(opt *pb.DeleteAttachmentOpts) error diff --git a/contrib/drivers/huawei/dorado/client.go b/contrib/drivers/huawei/dorado/client.go index 3ec8902f5..d1358a3ce 100644 --- a/contrib/drivers/huawei/dorado/client.go +++ b/contrib/drivers/huawei/dorado/client.go @@ -232,6 +232,17 @@ func (c *DoradoClient) DeleteVolume(id string) error { return err } +// ExtendVolume ... +func (c *DoradoClient) ExtendVolume(capacity int64, id string) error { + data := map[string]interface{}{ + "CAPACITY": capacity, + "ID": id, + } + + err := c.request("PUT", "/lun/expand", data, nil) + return err +} + func (c *DoradoClient) CreateSnapshot(volId, name, desc string) (*Snapshot, error) { data := map[string]interface{}{ "PARENTTYPE": 11, diff --git a/contrib/drivers/huawei/dorado/dorado.go b/contrib/drivers/huawei/dorado/dorado.go index 0a6ecb81c..ead057c91 100644 --- a/contrib/drivers/huawei/dorado/dorado.go +++ b/contrib/drivers/huawei/dorado/dorado.go @@ -135,6 +135,27 @@ func (d *Driver) DeleteVolume(opt *pb.DeleteVolumeOpts) error { return nil } +// ExtendVolume ... +func (d *Driver) ExtendVolume(opt *pb.ExtendVolumeOpts) (*model.VolumeSpec, error) { + //Convert the storage unit Giga to sector + err := d.client.ExtendVolume(d.gb2Sector(opt.GetSize()), opt.GetId()) + if err != nil { + log.Error("Extend Volume Failed:", err) + return nil, err + } + + log.Infof("Extend volume %s (%s) success.", opt.GetName(), opt.GetId()) + return &model.VolumeSpec{ + BaseModel: &model.BaseModel{ + Id: opt.GetId(), + }, + Name: opt.GetName(), + Size: opt.GetSize(), + Description: opt.GetDescription(), + AvailabilityZone: opt.GetAvailabilityZone(), + }, nil +} + func (d *Driver) getTargetInfo() (string, string, error) { tgtIp := d.conf.TargetIp resp, err := d.client.ListTgtPort() diff --git a/contrib/drivers/lvm/lvm.go b/contrib/drivers/lvm/lvm.go index aeea88e07..d61f12bdc 100755 --- a/contrib/drivers/lvm/lvm.go +++ b/contrib/drivers/lvm/lvm.go @@ -145,6 +145,36 @@ func (d *Driver) DeleteVolume(opt *pb.DeleteVolumeOpts) error { return nil } +// ExtendVolume ... +func (d *Driver) ExtendVolume(opt *pb.ExtendVolumeOpts) (*model.VolumeSpec, error) { + lvPath, ok := opt.GetMetadata()["lvPath"] + if !ok { + err := errors.New("failed to find logic volume path in volume metadata") + log.Error(err) + return nil, err + } + + var size = fmt.Sprint(opt.GetSize()) + "G" + + if _, err := d.handler("lvresize", []string{ + "-L", size, + lvPath, + }); err != nil { + log.Error("Failed to extend logic volume:", err) + return nil, err + } + + return &model.VolumeSpec{ + BaseModel: &model.BaseModel{ + Id: opt.GetId(), + }, + Name: opt.GetName(), + Size: opt.GetSize(), + Description: opt.GetDescription(), + Metadata: opt.GetMetadata(), + }, nil +} + func (d *Driver) InitializeConnection(opt *pb.CreateAttachmentOpts) (*model.ConnectionInfo, error) { var initiator string if initiator = opt.HostInfo.GetInitiator(); initiator == "" { @@ -292,7 +322,6 @@ func (d *Driver) getVGList() (*[]VolumeGroup, error) { return nil, err } - log.Info("Got vgs info:", info) lines := strings.Split(info, "\n") vgs := make([]VolumeGroup, len(lines)/vgInfoLineCount) @@ -358,10 +387,12 @@ func (*Driver) buildPoolParam(proper PoolProperties) *map[string]interface{} { } func execCmd(script string, cmd []string) (string, error) { + log.Infof("Command: %s %s", script, strings.Join(cmd, " ")) ret, err := exec.Command(script, cmd...).Output() if err != nil { log.Error(err.Error()) return "", err } + log.Infof("Command Result:\n%s", string(ret)) return string(ret), nil } diff --git a/contrib/drivers/lvm/lvm_test.go b/contrib/drivers/lvm/lvm_test.go index 53de690b7..639280194 100755 --- a/contrib/drivers/lvm/lvm_test.go +++ b/contrib/drivers/lvm/lvm_test.go @@ -73,6 +73,8 @@ func fakeHandler(script string, cmd []string) (string, error) { return string(sampleLV), nil case "lvremove": return "", nil + case "lvresize": + return "", nil case "vgdisplay": return string(sampleVG), nil default: @@ -134,6 +136,33 @@ func TestDeleteVolume(t *testing.T) { } } +func TestExtendVolume(t *testing.T) { + opt := &pb.ExtendVolumeOpts{ + Metadata: map[string]string{ + "lvPath": "/dev/vg001/test001", + }, + Size: int64(1), + } + + vol, err := fd.ExtendVolume(opt) + if err != nil { + t.Error("Failed to extend volume:", err) + } + + if vol.Size != 1 { + t.Errorf("Expected %+v, got %+v\n", 1, vol.Size) + } + + opt = &pb.ExtendVolumeOpts{ + Size: int64(1), + } + + vol, err = fd.ExtendVolume(opt) + if err.Error() != "failed to find logic volume path in volume metadata" { + t.Error("Error strings is not the same as expected:", err) + } +} + func TestCreateSnapshot(t *testing.T) { opt := &pb.CreateVolumeSnapshotOpts{ Name: "snap001", diff --git a/contrib/drivers/openstack/cinder/cinder.go b/contrib/drivers/openstack/cinder/cinder.go index a5711d89f..32a5f497c 100755 --- a/contrib/drivers/openstack/cinder/cinder.go +++ b/contrib/drivers/openstack/cinder/cinder.go @@ -214,6 +214,30 @@ func (d *Driver) DeleteVolume(opt *pb.DeleteVolumeOpts) error { return nil } +// ExtendVolume ... +func (d *Driver) ExtendVolume(req *pb.ExtendVolumeOpts) (*model.VolumeSpec, error) { + //Configure create request body. + opts := &volumeactions.ExtendSizeOpts{ + NewSize: int(req.GetSize()), + } + + err := volumeactions.ExtendSize(d.blockStoragev2, req.GetId(), opts).ExtractErr() + if err != nil { + log.Error("Cannot extend volume:", err) + return nil, err + } + + return &model.VolumeSpec{ + BaseModel: &model.BaseModel{ + Id: req.GetId(), + }, + Name: req.GetName(), + Description: req.GetDescription(), + Size: int64(req.GetSize()), + AvailabilityZone: req.GetAvailabilityZone(), + }, nil +} + // InitializeConnection func (d *Driver) InitializeConnection(req *pb.CreateAttachmentOpts) (*model.ConnectionInfo, error) { opts := &volumeactions.InitializeConnectionOpts{ diff --git a/contrib/drivers/openstack/cinder/cinder_test.go b/contrib/drivers/openstack/cinder/cinder_test.go index ad1cab472..bd4935939 100755 --- a/contrib/drivers/openstack/cinder/cinder_test.go +++ b/contrib/drivers/openstack/cinder/cinder_test.go @@ -29,6 +29,7 @@ import ( "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack" "github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/schedulerstats" + "github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions" snapshotsv2 "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/snapshots" volumesv2 "github.com/gophercloud/gophercloud/openstack/blockstorage/v2/volumes" "github.com/gophercloud/gophercloud/pagination" @@ -202,6 +203,28 @@ func TestPullVolume(t *testing.T) { } } +func TestExtendVolume(t *testing.T) { + defer monkey.UnpatchAll() + monkey.Patch(volumeactions.ExtendSize, + func(client *gophercloud.ServiceClient, id string, opts volumeactions.ExtendSizeOptsBuilder) (r volumeactions.ExtendSizeResult) { + return + }) + + opt := &pb.ExtendVolumeOpts{ + Name: "test1", + Description: "OpenSDS testing volume", + AvailabilityZone: "nova", + Size: 2, + } + d := Driver{} + _, err := d.ExtendVolume(opt) + + if err != nil { + t.Error("Extend volume error") + } + +} + func TestDeleteVolume(t *testing.T) { defer monkey.UnpatchAll() monkey.Patch(volumesv2.Delete, diff --git a/osdsctl/bin/osdsctl b/osdsctl/bin/osdsctl index 5a28eaddb..77d402745 100755 Binary files a/osdsctl/bin/osdsctl and b/osdsctl/bin/osdsctl differ diff --git a/osdsctl/cli/volume.go b/osdsctl/cli/volume.go index 530b02e51..60c8a79d1 100644 --- a/osdsctl/cli/volume.go +++ b/osdsctl/cli/volume.go @@ -64,6 +64,12 @@ var volumeUpdateCommand = &cobra.Command{ Run: volumeUpdateAction, } +var volumeExtendCommand = &cobra.Command{ + Use: "extend ", + Short: "extend a volume in the cluster", + Run: volumeExtendAction, +} + var ( profileId string volName string @@ -84,6 +90,7 @@ func init() { volumeCommand.AddCommand(volumeUpdateCommand) volumeUpdateCommand.Flags().StringVarP(&volName, "name", "n", "", "the name of updated volume") volumeUpdateCommand.Flags().StringVarP(&volDesp, "description", "d", "", "the description of updated volume") + volumeCommand.AddCommand(volumeExtendCommand) volumeCommand.AddCommand(volumeSnapshotCommand) volumeCommand.AddCommand(volumeAttachmentCommand) @@ -196,3 +203,29 @@ func volumeUpdateAction(cmd *cobra.Command, args []string) { "AvailabilityZone", "Status", "PoolId", "ProfileId", "Metadata"} PrintDict(resp, keys, FormatterList{}) } + +func volumeExtendAction(cmd *cobra.Command, args []string) { + if len(args) != 2 { + fmt.Fprintln(os.Stderr, "The number of args is not correct!") + cmd.Usage() + os.Exit(1) + } + + newSize, err := strconv.Atoi(args[1]) + if err != nil { + log.Fatalf("error parsing new size %s: %+v", args[1], err) + } + + body := &model.ExtendVolumeSpec{ + Extend: model.ExtendSpec{NewSize: int64(newSize)}, + } + + resp, err := client.ExtendVolume(args[0], body) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + keys := KeyList{"Id", "CreatedAt", "UpdatedAt", "Name", "Description", "Size", + "AvailabilityZone", "Status", "PoolId", "ProfileId", "Metadata"} + PrintDict(resp, keys, FormatterList{}) +} diff --git a/osdsctl/cli/volume_test.go b/osdsctl/cli/volume_test.go index 816ab46f5..bd990b315 100644 --- a/osdsctl/cli/volume_test.go +++ b/osdsctl/cli/volume_test.go @@ -78,3 +78,9 @@ func TestVolumeUpdateAction(t *testing.T) { args = append(args, "bd5b12a8-a101-11e7-941e-d77981b584d8") volumeUpdateAction(volumeDeleteCommand, args) } +func TestVolumeExtendAction(t *testing.T) { + var args []string + args = append(args, "bd5b12a8-a101-11e7-941e-d77981b584d8") + args = append(args, "5") + volumeExtendAction(volumeExtendCommand, args) +} diff --git a/osdsctl/cli/volumesnapshot.go b/osdsctl/cli/volumesnapshot.go index e11c11611..715a75185 100644 --- a/osdsctl/cli/volumesnapshot.go +++ b/osdsctl/cli/volumesnapshot.go @@ -52,7 +52,7 @@ var volumeSnapshotListCommand = &cobra.Command{ } var volumeSnapshotDeleteCommand = &cobra.Command{ - Use: "delete ", + Use: "delete ", Short: "delete a volume snapshot of specified volume in the cluster", Run: volumeSnapshotDeleteAction, } @@ -140,20 +140,18 @@ func volumeSnapshotListAction(cmd *cobra.Command, args []string) { } func volumeSnapshotDeleteAction(cmd *cobra.Command, args []string) { - if len(args) != 2 { + if len(args) != 1 { fmt.Fprintln(os.Stderr, "The number of args is not correct!") cmd.Usage() os.Exit(1) } - snp := &model.VolumeSnapshotSpec{ - VolumeId: args[0], - } - err := client.DeleteVolumeSnapshot(args[1], snp) + snapID := args[0] + err := client.DeleteVolumeSnapshot(snapID, nil) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } - fmt.Printf("Delete snapshot(%s) success.\n", args[1]) + fmt.Printf("Delete snapshot(%s) success.\n", snapID) } func volumeSnapshotUpdateAction(cmd *cobra.Command, args []string) { diff --git a/osdsctl/cli/volumesnapshot_test.go b/osdsctl/cli/volumesnapshot_test.go index 7cc49a285..eacfead5b 100644 --- a/osdsctl/cli/volumesnapshot_test.go +++ b/osdsctl/cli/volumesnapshot_test.go @@ -69,7 +69,6 @@ func TestVolumeSnapshotListAction(t *testing.T) { func TestVolumeSnapshotDeleteAction(t *testing.T) { var args []string - args = append(args, "bd5b12a8-a101-11e7-941e-d77981b584d8") args = append(args, "3769855c-a102-11e7-b772-17b880d2f537") volumeSnapshotDeleteAction(volumeSnapshotDeleteCommand, args) } diff --git a/pkg/api/router.go b/pkg/api/router.go index 7bdfc23d2..69b97b671 100755 --- a/pkg/api/router.go +++ b/pkg/api/router.go @@ -81,6 +81,8 @@ func Run(host string) { beego.NSRouter("/snapshots", &VolumeSnapshotPortal{}, "post:CreateVolumeSnapshot;get:ListVolumeSnapshots"), beego.NSRouter("/snapshots/:snapshotId", &VolumeSnapshotPortal{}, "get:GetVolumeSnapshot;put:UpdateVolumeSnapshot;delete:DeleteVolumeSnapshot"), ), + // Extend Volume + beego.NSRouter("/volumes/:volumeId/action", &VolumePortal{}, "post:ExtendVolume"), ) beego.AddNamespace(ns) diff --git a/pkg/api/volume.go b/pkg/api/volume.go index e63e6ab89..dfd180aff 100755 --- a/pkg/api/volume.go +++ b/pkg/api/volume.go @@ -142,7 +142,7 @@ func (this *VolumePortal) UpdateVolume() { } volume.Id = id - result, err := db.C.UpdateVolume(id, &volume) + result, err := db.C.UpdateVolume(&volume) if err != nil { reason := fmt.Sprintf("Update volume failed: %s", err.Error()) @@ -168,6 +168,63 @@ func (this *VolumePortal) UpdateVolume() { return } +// ExtendVolume ... +func (this *VolumePortal) ExtendVolume() { + var extendRequestBody = model.ExtendVolumeSpec{} + + if err := json.NewDecoder(this.Ctx.Request.Body).Decode(&extendRequestBody); err != nil { + reason := fmt.Sprintf("Parse volume request body failed: %s", err.Error()) + this.Ctx.Output.SetStatus(model.ErrorBadRequest) + this.Ctx.Output.Body(model.ErrorBadRequestStatus(reason)) + log.Error(reason) + return + } + + id := this.Ctx.Input.Param(":volumeId") + volume, err := db.C.GetVolume(id) + if err != nil { + reason := fmt.Sprintf("Get volume failed: %s", err.Error()) + this.Ctx.Output.SetStatus(model.ErrorBadRequest) + this.Ctx.Output.Body(model.ErrorBadRequestStatus(reason)) + log.Error(reason) + return + } + + if extendRequestBody.Extend.NewSize > volume.Size { + volume.Size = extendRequestBody.Extend.NewSize + } else { + reason := fmt.Sprintf("Extend volume failed: new size(%d) <= old size(%d)", + extendRequestBody.Extend.NewSize, volume.Size) + log.Error(reason) + return + } + + // Call global controller variable to handle extend volume request. + result, err := controller.Brain.ExtendVolume(volume) + if err != nil { + reason := fmt.Sprintf("Extend volume failed: %s", err.Error()) + this.Ctx.Output.SetStatus(model.ErrorBadRequest) + this.Ctx.Output.Body(model.ErrorBadRequestStatus(reason)) + log.Error(reason) + return + } + + // Marshal the result. + body, err := json.Marshal(result) + if err != nil { + reason := fmt.Sprintf("Marshal volume extended result failed: %s", err.Error()) + this.Ctx.Output.SetStatus(model.ErrorInternalServer) + this.Ctx.Output.Body(model.ErrorInternalServerStatus(reason)) + log.Error(reason) + return + } + + this.Ctx.Output.SetStatus(StatusOK) + this.Ctx.Output.Body(body) + + return +} + func (this *VolumePortal) DeleteVolume() { id := this.Ctx.Input.Param(":volumeId") volume, err := db.C.GetVolume(id) diff --git a/pkg/api/volume_test.go b/pkg/api/volume_test.go index 14402f74a..44f33e054 100755 --- a/pkg/api/volume_test.go +++ b/pkg/api/volume_test.go @@ -24,8 +24,10 @@ import ( "testing" "github.com/astaxie/beego" + "github.com/opensds/opensds/pkg/controller" "github.com/opensds/opensds/pkg/db" "github.com/opensds/opensds/pkg/model" + . "github.com/opensds/opensds/testutils/collection" dbtest "github.com/opensds/opensds/testutils/db/testing" ) @@ -35,6 +37,9 @@ func init() { beego.Router("/v1beta/block/volumes/:volumeId", &VolumePortal{}, "get:GetVolume;put:UpdateVolume;delete:DeleteVolume") + beego.Router("/v1beta/volumes/:volumeId/action", &VolumePortal{}, + "post:ExtendVolume") + beego.Router("/v1beta/block/attachments", &VolumeAttachmentPortal{}, "post:CreateVolumeAttachment;get:ListVolumeAttachments") beego.Router("/v1beta/block/attachments/:attachmentId", &VolumeAttachmentPortal{}, @@ -641,3 +646,41 @@ func TestUpdateVolumeAttachmentWithBadRequest(t *testing.T) { t.Errorf("Expected 400, actual %v", w.Code) } } + +func TestExtendVolumeWithBadRequest(t *testing.T) { + var extendVolume = model.ExtendVolumeSpec{ + Extend: model.ExtendSpec{NewSize: 123}, + } + + extendVolumeByte, err := json.Marshal(extendVolume) + if err != nil { + t.Errorf("%v", err) + } + + extendVolumeStr := string(extendVolumeByte) + if extendVolumeStr != "{\"extend\":{\"newSize\":123}}" { + t.Errorf("Expected {\"extend\":{\"newSize\":123}}, actual %v", extendVolumeStr) + } + + var jsonStr = []byte(`{"extend":{"newSize": 0}}`) + r, _ := http.NewRequest("POST", + "/v1beta/volumes/bd5b12a8-a101-11e7-941e-d77981b584d8/action", bytes.NewBuffer(jsonStr)) + w := httptest.NewRecorder() + r.Header.Set("Content-Type", "application/JSON") + + var ExtendVolumeBody = model.ExtendVolumeSpec{ + Extend: model.ExtendSpec{}, + } + + json.NewDecoder(bytes.NewBuffer(jsonStr)).Decode(&ExtendVolumeBody) + + mockClient := new(dbtest.MockClient) + mockClient.On("GetVolume", "bd5b12a8-a101-11e7-941e-d77981b584d8").Return(&SampleVolumes[0], nil) + db.C = mockClient + controller.Brain = controller.NewController() + beego.BeeApp.Handlers.ServeHTTP(w, r) + + if w.Code != 500 { + t.Errorf("Expected 500, actual %v", w.Code) + } +} diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index 9355dfa27..cadaf992a 100755 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -38,6 +38,7 @@ const ( GET_LIFECIRCLE_FLAG LIST_LIFECIRCLE_FLAG DELETE_LIFECIRCLE_FLAG + EXTEND_LIFECIRCLE_FLAG ) var Brain *Controller @@ -168,6 +169,51 @@ func (c *Controller) DeleteVolume(in *model.VolumeSpec) error { return c.volumeController.DeleteVolume(opt) } +// ExtendVolume ... +func (c *Controller) ExtendVolume(in *model.VolumeSpec) (*model.VolumeSpec, error) { + prf, err := db.C.GetProfile(in.ProfileId) + if err != nil { + log.Error("when search profile in db:", err) + return nil, err + } + + // Select the storage tag according to the lifecycle flag. + c.policyController = policy.NewController(prf) + c.policyController.Setup(EXTEND_LIFECIRCLE_FLAG) + + dockInfo, err := db.C.GetDockByPoolId(in.PoolId) + if err != nil { + log.Error("When search dock in db by pool id: ", err) + return nil, err + } + c.policyController.SetDock(dockInfo) + c.volumeController.SetDock(dockInfo) + + opt := &pb.ExtendVolumeOpts{ + Id: in.Id, + Size: in.Size, + Metadata: in.Metadata, + DockId: dockInfo.Id, + DriverName: dockInfo.DriverName, + } + + result, err := c.volumeController.ExtendVolume(opt) + if err != nil { + return nil, err + } + + volBody, _ := json.Marshal(result) + var errChan = make(chan error, 1) + go c.policyController.ExecuteAsyncPolicy(opt, string(volBody), errChan) + + if err := <-errChan; err != nil { + log.Error("When execute async policy:", err) + return nil, err + } + + return result, nil +} + func (c *Controller) CreateVolumeAttachment(in *model.VolumeAttachmentSpec) (*model.VolumeAttachmentSpec, error) { vol, err := db.C.GetVolume(in.VolumeId) if err != nil { diff --git a/pkg/controller/controller_test.go b/pkg/controller/controller_test.go index 5c168d88b..f32f2fb8f 100755 --- a/pkg/controller/controller_test.go +++ b/pkg/controller/controller_test.go @@ -53,6 +53,10 @@ func (fvc *fakeVolumeController) DeleteVolume(*pb.DeleteVolumeOpts) error { return nil } +func (fvc *fakeVolumeController) ExtendVolume(*pb.ExtendVolumeOpts) (*model.VolumeSpec, error) { + return &SampleVolumes[0], nil +} + func (fvc *fakeVolumeController) CreateVolumeAttachment(*pb.CreateAttachmentOpts) (*model.VolumeAttachmentSpec, error) { return &SampleAttachments[0], nil } @@ -130,6 +134,40 @@ func TestDeleteVolume(t *testing.T) { } } +func TestExtendVolume(t *testing.T) { + mockClient := new(dbtest.MockClient) + mockClient.On("GetDefaultProfile").Return(&SampleProfiles[0], nil) + mockClient.On("GetProfile", "1106b972-66ef-11e7-b172-db03f3689c9c").Return(&SampleProfiles[0], nil) + mockClient.On("GetDockByPoolId", "084bf71e-a102-11e7-88a8-e31fe6d52248").Return(&SampleDocks[0], nil) + mockClient.On("GetDock", "b7602e18-771e-11e7-8f38-dbd6d291f4e0").Return(&SampleDocks[0], nil) + db.C = mockClient + + var req = &model.VolumeSpec{ + BaseModel: &model.BaseModel{}, + Name: "sample-volume", + Description: "This is a sample volume for testing", + Size: int64(1), + ProfileId: "1106b972-66ef-11e7-b172-db03f3689c9c", + PoolId: "084bf71e-a102-11e7-88a8-e31fe6d52248", + } + var c = &Controller{ + selector: &fakeSelector{ + res: &model.StoragePoolSpec{BaseModel: &model.BaseModel{}, DockId: "b7602e18-771e-11e7-8f38-dbd6d291f4e0"}, + err: nil, + }, + volumeController: NewFakeVolumeController(), + } + var expected = &SampleVolumes[0] + + result, err := c.ExtendVolume(req) + if err != nil { + t.Errorf("Failed to create volume, err is %v\n", err) + } + if !reflect.DeepEqual(result, expected) { + t.Errorf("Expected %v, got %v\n", expected, result) + } +} + func TestCreateVolumeAttachment(t *testing.T) { mockClient := new(dbtest.MockClient) mockClient.On("GetVolume", "bd5b12a8-a101-11e7-941e-d77981b584d8").Return(&SampleVolumes[0], nil) diff --git a/pkg/controller/volume/volumecontroller.go b/pkg/controller/volume/volumecontroller.go index 65547abf2..96d5b267b 100755 --- a/pkg/controller/volume/volumecontroller.go +++ b/pkg/controller/volume/volumecontroller.go @@ -38,6 +38,8 @@ type Controller interface { DeleteVolume(opt *pb.DeleteVolumeOpts) error + ExtendVolume(opt *pb.ExtendVolumeOpts) (*model.VolumeSpec, error) + CreateVolumeAttachment(opt *pb.CreateAttachmentOpts) (*model.VolumeAttachmentSpec, error) DeleteVolumeAttachment(opt *pb.DeleteAttachmentOpts) error @@ -110,6 +112,34 @@ func (c *controller) DeleteVolume(opt *pb.DeleteVolumeOpts) error { return nil } +func (c *controller) ExtendVolume(opt *pb.ExtendVolumeOpts) (*model.VolumeSpec, error) { + if err := c.Client.Connect(c.DockInfo.Endpoint); err != nil { + log.Error("When connecting dock client:", err) + return nil, err + } + + response, err := c.Client.ExtendVolume(context.Background(), opt) + if err != nil { + log.Error("extend volume failed in volume controller:", err) + return nil, err + } + defer c.Client.Close() + + if errorMsg := response.GetError(); errorMsg != nil { + return nil, + fmt.Errorf("failed to extend volume in volume controller, code: %v, message: %v", + errorMsg.GetCode(), errorMsg.GetDescription()) + } + + var vol = &model.VolumeSpec{} + if err = json.Unmarshal([]byte(response.GetResult().GetMessage()), vol); err != nil { + log.Error("extend volume failed in volume controller:", err) + return nil, err + } + + return vol, nil +} + func (c *controller) CreateVolumeAttachment(opt *pb.CreateAttachmentOpts) (*model.VolumeAttachmentSpec, error) { if err := c.Client.Connect(c.DockInfo.Endpoint); err != nil { log.Error("When connecting dock client:", err) diff --git a/pkg/controller/volume/volumecontroller_test.go b/pkg/controller/volume/volumecontroller_test.go index 68222f29d..2b4d0c40c 100755 --- a/pkg/controller/volume/volumecontroller_test.go +++ b/pkg/controller/volume/volumecontroller_test.go @@ -60,6 +60,17 @@ func (fc *fakeClient) DeleteVolume(ctx context.Context, in *pb.DeleteVolumeOpts, }, nil } +// Extend a volume +func (fc *fakeClient) ExtendVolume(ctx context.Context, in *pb.ExtendVolumeOpts, opts ...grpc.CallOption) (*pb.GenericResponse, error) { + return &pb.GenericResponse{ + Reply: &pb.GenericResponse_Result_{ + Result: &pb.GenericResponse_Result{ + Message: ByteVolume, + }, + }, + }, nil +} + // Create a volume attachment func (fc *fakeClient) CreateAttachment(ctx context.Context, in *pb.CreateAttachmentOpts, opts ...grpc.CallOption) (*pb.GenericResponse, error) { return &pb.GenericResponse{ @@ -129,6 +140,20 @@ func TestDeleteVolume(t *testing.T) { } } +func TestExtendVolume(t *testing.T) { + fc := NewFakeController() + var expected = &SampleVolumes[0] + + result, err := fc.ExtendVolume(&pb.ExtendVolumeOpts{}) + if err != nil { + t.Errorf("Failed to extend volume, err is %v\n", err) + } + + if !reflect.DeepEqual(result, expected) { + t.Errorf("Expected %v, got %v\n", expected, result) + } +} + func TestCreateVolumeAttachment(t *testing.T) { fc := NewFakeController() var expected = &SampleAttachments[0] diff --git a/pkg/db/db.go b/pkg/db/db.go index 38b24ba67..c62cf1209 100755 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -101,10 +101,12 @@ type Client interface { ListVolumes() ([]*model.VolumeSpec, error) - UpdateVolume(volID string, vol *model.VolumeSpec) (*model.VolumeSpec, error) + UpdateVolume(vol *model.VolumeSpec) (*model.VolumeSpec, error) DeleteVolume(volID string) error + ExtendVolume(vol *model.VolumeSpec) (*model.VolumeSpec, error) + CreateVolumeAttachment(attachment *model.VolumeAttachmentSpec) (*model.VolumeAttachmentSpec, error) GetVolumeAttachment(attachmentId string) (*model.VolumeAttachmentSpec, error) diff --git a/pkg/db/drivers/etcd/client.go b/pkg/db/drivers/etcd/client.go index cda60406c..66120bcb4 100755 --- a/pkg/db/drivers/etcd/client.go +++ b/pkg/db/drivers/etcd/client.go @@ -20,11 +20,13 @@ import ( "github.com/coreos/etcd/clientv3" log "github.com/golang/glog" + "github.com/opensds/opensds/pkg/utils" "golang.org/x/net/context" ) var ( - timeOut = 3 * time.Second + timeOut = 3 * time.Second + retryNum = 3 ) // Request @@ -55,15 +57,18 @@ type clientInterface interface { // Init func Init(edps []string) *client { - cliv3, err := clientv3.New(clientv3.Config{ - Endpoints: edps, - DialTimeout: timeOut, + var cliv3 *clientv3.Client + err := utils.Retry(retryNum, "Get etcd client", func() error { + var err error + cliv3, err = clientv3.New(clientv3.Config{ + Endpoints: edps, + DialTimeout: timeOut, + }) + return err }) if err != nil { - cliv3.Close() panic(err) } - return &client{cli: cliv3} } @@ -79,7 +84,11 @@ func (c *client) Create(req *Request) *Response { c.lock.Lock() defer c.lock.Unlock() - _, err := c.cli.Put(ctx, req.Url, req.Content) + err := utils.Retry(retryNum, "Etcd put", func() error { + _, err := c.cli.Put(ctx, req.Url, req.Content) + return err + }) + if err != nil { log.Error("When create db request:", err) return &Response{ diff --git a/pkg/db/drivers/etcd/etcd.go b/pkg/db/drivers/etcd/etcd.go index 74b5f3bf8..05d0042e0 100755 --- a/pkg/db/drivers/etcd/etcd.go +++ b/pkg/db/drivers/etcd/etcd.go @@ -561,9 +561,9 @@ func (c *Client) ListVolumes() ([]*model.VolumeSpec, error) { return vols, nil } -// UpdateVolume -func (c *Client) UpdateVolume(volID string, vol *model.VolumeSpec) (*model.VolumeSpec, error) { - result, err := c.GetVolume(volID) +// UpdateVolume ... +func (c *Client) UpdateVolume(vol *model.VolumeSpec) (*model.VolumeSpec, error) { + result, err := c.GetVolume(vol.Id) if err != nil { return nil, err } @@ -579,14 +579,14 @@ func (c *Client) UpdateVolume(volID string, vol *model.VolumeSpec) (*model.Volum // Set update time result.UpdatedAt = time.Now().Format(constants.TimeFormat) - atcBody, err := json.Marshal(result) + body, err := json.Marshal(result) if err != nil { return nil, err } dbReq := &Request{ - Url: urls.GenerateVolumeURL(volID), - NewContent: string(atcBody), + Url: urls.GenerateVolumeURL(vol.Id), + NewContent: string(body), } dbRes := c.Update(dbReq) @@ -610,6 +610,38 @@ func (c *Client) DeleteVolume(volID string) error { return nil } +// ExtendVolume ... +func (c *Client) ExtendVolume(vol *model.VolumeSpec) (*model.VolumeSpec, error) { + result, err := c.GetVolume(vol.Id) + if err != nil { + return nil, err + } + + if vol.Size > 0 { + result.Size = vol.Size + } + + // Set update time + result.UpdatedAt = time.Now().Format(constants.TimeFormat) + + body, err := json.Marshal(result) + if err != nil { + return nil, err + } + + dbReq := &Request{ + Url: urls.GenerateVolumeURL(vol.Id), + NewContent: string(body), + } + + dbRes := c.Update(dbReq) + if dbRes.Status != "Success" { + log.Error("When extend volume in db:", dbRes.Error) + return nil, errors.New(dbRes.Error) + } + return result, nil +} + // CreateVolumeAttachment func (c *Client) CreateVolumeAttachment(attachment *model.VolumeAttachmentSpec) (*model.VolumeAttachmentSpec, error) { if attachment.Id == "" { diff --git a/pkg/db/drivers/etcd/etcd_test.go b/pkg/db/drivers/etcd/etcd_test.go index d5ff636f3..1b47895c4 100644 --- a/pkg/db/drivers/etcd/etcd_test.go +++ b/pkg/db/drivers/etcd/etcd_test.go @@ -279,11 +279,14 @@ func TestListVolumes(t *testing.T) { func TestUpdateVolume(t *testing.T) { var vol = model.VolumeSpec{ + BaseModel: &model.BaseModel{ + Id: "bd5b12a8-a101-11e7-941e-d77981b584d8", + }, Name: "Test Name", Description: "Test Description", } - result, err := fc.UpdateVolume("bd5b12a8-a101-11e7-941e-d77981b584d8", &vol) + result, err := fc.UpdateVolume(&vol) if err != nil { t.Error("Update volumes failed:", err) } @@ -460,3 +463,27 @@ func TestDeleteVolumeSnapshot(t *testing.T) { t.Error("Delete volume snapshot failed:", err) } } + +func TestExtendVolume(t *testing.T) { + var vol = model.VolumeSpec{ + BaseModel: &model.BaseModel{ + Id: "bd5b12a8-a101-11e7-941e-d77981b584d8", + }, + Name: "sample-volume", + Description: "This is a sample volume for testing", + Size: 9, + } + + result, err := fc.ExtendVolume(&vol) + if err != nil { + t.Error("Extend volumes failed:", err) + } + + if result.Id != "bd5b12a8-a101-11e7-941e-d77981b584d8" { + t.Errorf("Expected %+v, got %+v\n", "bd5b12a8-a101-11e7-941e-d77981b584d8", result.Id) + } + + if result.Size != 9 { + t.Errorf("Expected %+v, got %+v\n", 9, result.Size) + } +} diff --git a/pkg/dock/discovery/discovery.go b/pkg/dock/discovery/discovery.go index a40ec8bb1..d85e0f765 100755 --- a/pkg/dock/discovery/discovery.go +++ b/pkg/dock/discovery/discovery.go @@ -20,6 +20,7 @@ This module implements the entry into operations of storageDock module. package discovery import ( + "fmt" "os" log "github.com/golang/glog" @@ -78,17 +79,15 @@ func (dd *DockDiscoverer) Init() error { // Discover func (dd *DockDiscoverer) Discover(d drivers.VolumeDriver) error { - var pols []*model.StoragePoolSpec - var err error for _, dck := range dd.dcks { //Call function of StorageDrivers configured by storage drivers. d = drivers.Init(dck.DriverName) defer drivers.Clean(d) - pols, err = d.ListPools() + pols, err := d.ListPools() if err != nil { log.Error("Call driver to list pools failed:", err) - return err + continue } if len(pols) == 0 { @@ -101,8 +100,10 @@ func (dd *DockDiscoverer) Discover(d drivers.VolumeDriver) error { } dd.pols = append(dd.pols, pols...) } - - return err + if len(dd.pols) == 0 { + return fmt.Errorf("There is no pool can be found.") + } + return nil } // Store diff --git a/pkg/dock/dock.go b/pkg/dock/dock.go index 290087cd6..322cde8f9 100755 --- a/pkg/dock/dock.go +++ b/pkg/dock/dock.go @@ -114,6 +114,32 @@ func (d *DockHub) DeleteVolume(opt *pb.DeleteVolumeOpts) error { return nil } +// ExtendVolume ... +func (d *DockHub) ExtendVolume(opt *pb.ExtendVolumeOpts) (*model.VolumeSpec, error) { + //Get the storage drivers and do some initializations. + d.Driver = drivers.Init(opt.GetDriverName()) + defer drivers.Clean(d.Driver) + + log.Info("Calling volume driver to extend volume...") + + //Call function of StorageDrivers configured by storage drivers. + vol, err := d.Driver.ExtendVolume(opt) + if err != nil { + log.Error("When calling volume driver to extend volume:", err) + return nil, err + } + + vol.PoolId, vol.ProfileId = opt.GetPoolId(), opt.GetProfileId() + // Store the volume data into database. + result, err := db.C.ExtendVolume(vol) + if err != nil { + log.Error("When extend volume in db module:", err) + return nil, err + } + + return result, nil +} + // CreateVolumeAttachment func (d *DockHub) CreateVolumeAttachment(opt *pb.CreateAttachmentOpts) (*model.VolumeAttachmentSpec, error) { //Get the storage drivers and do some initializations. diff --git a/pkg/dock/proto/dock.pb.go b/pkg/dock/proto/dock.pb.go index 8368b7024..e7eb2a93f 100755 --- a/pkg/dock/proto/dock.pb.go +++ b/pkg/dock/proto/dock.pb.go @@ -10,6 +10,7 @@ It is generated from these files: It has these top-level messages: CreateVolumeOpts DeleteVolumeOpts + ExtendVolumeOpts CreateVolumeSnapshotOpts DeleteVolumeSnapshotOpts CreateAttachmentOpts @@ -203,6 +204,124 @@ func (m *DeleteVolumeOpts) GetDriverName() string { return "" } +// ExtendVolumeOpts is a structure which indicates all required properties +// for Extending a volume. +type ExtendVolumeOpts struct { + // The uuid of the volume, optional when creating. + Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` + // The name of the volume, required. + Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` + // The requested capacity of the volume, required. + Size int64 `protobuf:"varint,3,opt,name=size" json:"size,omitempty"` + // The description of the volume, optional. + Description string `protobuf:"bytes,4,opt,name=description" json:"description,omitempty"` + // When create volume from snapshot, this field is required. + SnapshotId string `protobuf:"bytes,5,opt,name=snapshotId" json:"snapshotId,omitempty"` + // The locality that volume belongs to, required. + AvailabilityZone string `protobuf:"bytes,6,opt,name=availabilityZone" json:"availabilityZone,omitempty"` + // The service level that volume belongs to, required. + ProfileId string `protobuf:"bytes,7,opt,name=profileId" json:"profileId,omitempty"` + // The uuid of the pool on which volume will be created, required. + PoolId string `protobuf:"bytes,8,opt,name=poolId" json:"poolId,omitempty"` + // The name of the pool on which volume will be created, required. + PoolName string `protobuf:"bytes,9,opt,name=poolName" json:"poolName,omitempty"` + // The metadata of the volume, optional. + Metadata map[string]string `protobuf:"bytes,10,rep,name=metadata" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + // The dock infomation on which the request will be executed + DockId string `protobuf:"bytes,11,opt,name=dockId" json:"dockId,omitempty"` + // The storage driver type. + DriverName string `protobuf:"bytes,12,opt,name=driverName" json:"driverName,omitempty"` +} + +func (m *ExtendVolumeOpts) Reset() { *m = ExtendVolumeOpts{} } +func (m *ExtendVolumeOpts) String() string { return proto1.CompactTextString(m) } +func (*ExtendVolumeOpts) ProtoMessage() {} +func (*ExtendVolumeOpts) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *ExtendVolumeOpts) GetId() string { + if m != nil { + return m.Id + } + return "" +} + +func (m *ExtendVolumeOpts) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *ExtendVolumeOpts) GetSize() int64 { + if m != nil { + return m.Size + } + return 0 +} + +func (m *ExtendVolumeOpts) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *ExtendVolumeOpts) GetSnapshotId() string { + if m != nil { + return m.SnapshotId + } + return "" +} + +func (m *ExtendVolumeOpts) GetAvailabilityZone() string { + if m != nil { + return m.AvailabilityZone + } + return "" +} + +func (m *ExtendVolumeOpts) GetProfileId() string { + if m != nil { + return m.ProfileId + } + return "" +} + +func (m *ExtendVolumeOpts) GetPoolId() string { + if m != nil { + return m.PoolId + } + return "" +} + +func (m *ExtendVolumeOpts) GetPoolName() string { + if m != nil { + return m.PoolName + } + return "" +} + +func (m *ExtendVolumeOpts) GetMetadata() map[string]string { + if m != nil { + return m.Metadata + } + return nil +} + +func (m *ExtendVolumeOpts) GetDockId() string { + if m != nil { + return m.DockId + } + return "" +} + +func (m *ExtendVolumeOpts) GetDriverName() string { + if m != nil { + return m.DriverName + } + return "" +} + // CreateVolumeSnapshotOpts is a structure which indicates all required // properties for creating a volume snapshot. type CreateVolumeSnapshotOpts struct { @@ -227,7 +346,7 @@ type CreateVolumeSnapshotOpts struct { func (m *CreateVolumeSnapshotOpts) Reset() { *m = CreateVolumeSnapshotOpts{} } func (m *CreateVolumeSnapshotOpts) String() string { return proto1.CompactTextString(m) } func (*CreateVolumeSnapshotOpts) ProtoMessage() {} -func (*CreateVolumeSnapshotOpts) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } +func (*CreateVolumeSnapshotOpts) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } func (m *CreateVolumeSnapshotOpts) GetId() string { if m != nil { @@ -303,7 +422,7 @@ type DeleteVolumeSnapshotOpts struct { func (m *DeleteVolumeSnapshotOpts) Reset() { *m = DeleteVolumeSnapshotOpts{} } func (m *DeleteVolumeSnapshotOpts) String() string { return proto1.CompactTextString(m) } func (*DeleteVolumeSnapshotOpts) ProtoMessage() {} -func (*DeleteVolumeSnapshotOpts) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } +func (*DeleteVolumeSnapshotOpts) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } func (m *DeleteVolumeSnapshotOpts) GetId() string { if m != nil { @@ -364,7 +483,7 @@ type CreateAttachmentOpts struct { func (m *CreateAttachmentOpts) Reset() { *m = CreateAttachmentOpts{} } func (m *CreateAttachmentOpts) String() string { return proto1.CompactTextString(m) } func (*CreateAttachmentOpts) ProtoMessage() {} -func (*CreateAttachmentOpts) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } +func (*CreateAttachmentOpts) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } func (m *CreateAttachmentOpts) GetId() string { if m != nil { @@ -442,7 +561,7 @@ type DeleteAttachmentOpts struct { func (m *DeleteAttachmentOpts) Reset() { *m = DeleteAttachmentOpts{} } func (m *DeleteAttachmentOpts) String() string { return proto1.CompactTextString(m) } func (*DeleteAttachmentOpts) ProtoMessage() {} -func (*DeleteAttachmentOpts) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } +func (*DeleteAttachmentOpts) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } func (m *DeleteAttachmentOpts) GetId() string { if m != nil { @@ -502,7 +621,7 @@ type HostInfo struct { func (m *HostInfo) Reset() { *m = HostInfo{} } func (m *HostInfo) String() string { return proto1.CompactTextString(m) } func (*HostInfo) ProtoMessage() {} -func (*HostInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } +func (*HostInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } func (m *HostInfo) GetPlatform() string { if m != nil { @@ -553,7 +672,7 @@ type GenericResponse struct { func (m *GenericResponse) Reset() { *m = GenericResponse{} } func (m *GenericResponse) String() string { return proto1.CompactTextString(m) } func (*GenericResponse) ProtoMessage() {} -func (*GenericResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } +func (*GenericResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } type isGenericResponse_Reply interface { isGenericResponse_Reply() @@ -671,7 +790,7 @@ type GenericResponse_Result struct { func (m *GenericResponse_Result) Reset() { *m = GenericResponse_Result{} } func (m *GenericResponse_Result) String() string { return proto1.CompactTextString(m) } func (*GenericResponse_Result) ProtoMessage() {} -func (*GenericResponse_Result) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7, 0} } +func (*GenericResponse_Result) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8, 0} } func (m *GenericResponse_Result) GetMessage() string { if m != nil { @@ -688,7 +807,7 @@ type GenericResponse_Error struct { func (m *GenericResponse_Error) Reset() { *m = GenericResponse_Error{} } func (m *GenericResponse_Error) String() string { return proto1.CompactTextString(m) } func (*GenericResponse_Error) ProtoMessage() {} -func (*GenericResponse_Error) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7, 1} } +func (*GenericResponse_Error) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8, 1} } func (m *GenericResponse_Error) GetCode() string { if m != nil { @@ -707,6 +826,7 @@ func (m *GenericResponse_Error) GetDescription() string { func init() { proto1.RegisterType((*CreateVolumeOpts)(nil), "proto.CreateVolumeOpts") proto1.RegisterType((*DeleteVolumeOpts)(nil), "proto.DeleteVolumeOpts") + proto1.RegisterType((*ExtendVolumeOpts)(nil), "proto.ExtendVolumeOpts") proto1.RegisterType((*CreateVolumeSnapshotOpts)(nil), "proto.CreateVolumeSnapshotOpts") proto1.RegisterType((*DeleteVolumeSnapshotOpts)(nil), "proto.DeleteVolumeSnapshotOpts") proto1.RegisterType((*CreateAttachmentOpts)(nil), "proto.CreateAttachmentOpts") @@ -732,6 +852,8 @@ type DockClient interface { CreateVolume(ctx context.Context, in *CreateVolumeOpts, opts ...grpc.CallOption) (*GenericResponse, error) // Delete a volume DeleteVolume(ctx context.Context, in *DeleteVolumeOpts, opts ...grpc.CallOption) (*GenericResponse, error) + // Extend a volume + ExtendVolume(ctx context.Context, in *ExtendVolumeOpts, opts ...grpc.CallOption) (*GenericResponse, error) // Create a volume snapshot CreateVolumeSnapshot(ctx context.Context, in *CreateVolumeSnapshotOpts, opts ...grpc.CallOption) (*GenericResponse, error) // Delete a volume snapshot @@ -768,6 +890,15 @@ func (c *dockClient) DeleteVolume(ctx context.Context, in *DeleteVolumeOpts, opt return out, nil } +func (c *dockClient) ExtendVolume(ctx context.Context, in *ExtendVolumeOpts, opts ...grpc.CallOption) (*GenericResponse, error) { + out := new(GenericResponse) + err := grpc.Invoke(ctx, "/proto.Dock/ExtendVolume", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *dockClient) CreateVolumeSnapshot(ctx context.Context, in *CreateVolumeSnapshotOpts, opts ...grpc.CallOption) (*GenericResponse, error) { out := new(GenericResponse) err := grpc.Invoke(ctx, "/proto.Dock/CreateVolumeSnapshot", in, out, c.cc, opts...) @@ -811,6 +942,8 @@ type DockServer interface { CreateVolume(context.Context, *CreateVolumeOpts) (*GenericResponse, error) // Delete a volume DeleteVolume(context.Context, *DeleteVolumeOpts) (*GenericResponse, error) + // Extend a volume + ExtendVolume(context.Context, *ExtendVolumeOpts) (*GenericResponse, error) // Create a volume snapshot CreateVolumeSnapshot(context.Context, *CreateVolumeSnapshotOpts) (*GenericResponse, error) // Delete a volume snapshot @@ -861,6 +994,24 @@ func _Dock_DeleteVolume_Handler(srv interface{}, ctx context.Context, dec func(i return interceptor(ctx, in, info, handler) } +func _Dock_ExtendVolume_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ExtendVolumeOpts) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DockServer).ExtendVolume(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.Dock/ExtendVolume", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DockServer).ExtendVolume(ctx, req.(*ExtendVolumeOpts)) + } + return interceptor(ctx, in, info, handler) +} + func _Dock_CreateVolumeSnapshot_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(CreateVolumeSnapshotOpts) if err := dec(in); err != nil { @@ -945,6 +1096,10 @@ var _Dock_serviceDesc = grpc.ServiceDesc{ MethodName: "DeleteVolume", Handler: _Dock_DeleteVolume_Handler, }, + { + MethodName: "ExtendVolume", + Handler: _Dock_ExtendVolume_Handler, + }, { MethodName: "CreateVolumeSnapshot", Handler: _Dock_CreateVolumeSnapshot_Handler, @@ -969,54 +1124,56 @@ var _Dock_serviceDesc = grpc.ServiceDesc{ func init() { proto1.RegisterFile("dock.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 771 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xcc, 0x96, 0xcf, 0x6f, 0xd3, 0x30, - 0x14, 0xc7, 0xd7, 0xa4, 0x69, 0xb3, 0xd7, 0x8d, 0x55, 0xd6, 0x34, 0xa2, 0x32, 0xa0, 0xaa, 0x40, - 0x1a, 0x20, 0x7a, 0x28, 0x48, 0x20, 0x10, 0x87, 0xc1, 0x26, 0x56, 0x89, 0x9f, 0x01, 0x71, 0xe0, - 0xe6, 0x35, 0x1e, 0xb5, 0x96, 0xc4, 0x91, 0xe3, 0x56, 0x2a, 0x27, 0x4e, 0xfc, 0x33, 0xfc, 0x17, - 0x9c, 0x38, 0x72, 0xe6, 0x6f, 0x40, 0xe2, 0x5f, 0x40, 0x76, 0x9c, 0x34, 0xe9, 0xda, 0xd0, 0x89, - 0x22, 0x71, 0xaa, 0xdf, 0xf3, 0xf3, 0xb3, 0xbf, 0x1f, 0x3f, 0xbf, 0x14, 0xc0, 0x63, 0x83, 0xd3, - 0x6e, 0xc4, 0x99, 0x60, 0xc8, 0x52, 0x3f, 0x9d, 0xaf, 0x26, 0x34, 0x9f, 0x70, 0x82, 0x05, 0x79, - 0xc7, 0xfc, 0x51, 0x40, 0x5e, 0x46, 0x22, 0x46, 0x17, 0xc0, 0xa0, 0x9e, 0x53, 0x69, 0x57, 0xf6, - 0xd6, 0x5d, 0x83, 0x7a, 0x08, 0x41, 0x35, 0xc4, 0x01, 0x71, 0x0c, 0xe5, 0x51, 0x63, 0xe9, 0x8b, - 0xe9, 0x47, 0xe2, 0x98, 0xed, 0xca, 0x9e, 0xe9, 0xaa, 0x31, 0x6a, 0x43, 0xc3, 0x23, 0xf1, 0x80, - 0xd3, 0x48, 0x50, 0x16, 0x3a, 0x55, 0x15, 0x9e, 0x77, 0xa1, 0x2b, 0x00, 0x71, 0x88, 0xa3, 0x78, - 0xc8, 0x44, 0xdf, 0x73, 0x2c, 0x15, 0x90, 0xf3, 0xa0, 0x9b, 0xd0, 0xc4, 0x63, 0x4c, 0x7d, 0x7c, - 0x4c, 0x7d, 0x2a, 0x26, 0xef, 0x59, 0x48, 0x9c, 0x9a, 0x8a, 0x3a, 0xe3, 0x47, 0xbb, 0xb0, 0x1e, - 0x71, 0x76, 0x42, 0x7d, 0xd2, 0xf7, 0x9c, 0xba, 0x0a, 0x9a, 0x3a, 0xd0, 0x0e, 0xd4, 0x22, 0xc6, - 0xfc, 0xbe, 0xe7, 0xd8, 0x6a, 0x4a, 0x5b, 0xa8, 0x05, 0xb6, 0x1c, 0xbd, 0x90, 0x7a, 0xd6, 0xd5, - 0x4c, 0x66, 0xa3, 0x7d, 0xb0, 0x03, 0x22, 0xb0, 0x87, 0x05, 0x76, 0xa0, 0x6d, 0xee, 0x35, 0x7a, - 0xd7, 0x13, 0x5a, 0xdd, 0x59, 0x44, 0xdd, 0xe7, 0x3a, 0xee, 0x30, 0x14, 0x7c, 0xe2, 0x66, 0xcb, - 0xe4, 0xb6, 0x12, 0x72, 0xdf, 0x73, 0x1a, 0xc9, 0xb6, 0x89, 0x25, 0x85, 0x7b, 0x9c, 0x8e, 0x09, - 0x57, 0x1b, 0x6f, 0x24, 0xc2, 0xa7, 0x9e, 0xd6, 0x43, 0xd8, 0x2c, 0xa4, 0x44, 0x4d, 0x30, 0x4f, - 0xc9, 0x44, 0x5f, 0x82, 0x1c, 0xa2, 0x6d, 0xb0, 0xc6, 0xd8, 0x1f, 0xa5, 0xd7, 0x90, 0x18, 0x0f, - 0x8c, 0xfb, 0x95, 0xce, 0x8f, 0x0a, 0x34, 0x0f, 0x88, 0x4f, 0x4a, 0x2f, 0x31, 0x2f, 0xce, 0x28, - 0x88, 0x9b, 0x5d, 0xba, 0x84, 0x38, 0xb3, 0x44, 0x5c, 0x75, 0xb5, 0xe2, 0xbe, 0x1b, 0xe0, 0xe4, - 0xf1, 0xbf, 0xd1, 0xd5, 0xf2, 0x8f, 0x2b, 0xb5, 0x05, 0xf6, 0x58, 0xed, 0x97, 0xd5, 0x69, 0x66, - 0xa3, 0x7e, 0x0e, 0x65, 0x4d, 0xa1, 0xbc, 0x3d, 0xa7, 0x4e, 0xf2, 0x07, 0x5d, 0x02, 0x69, 0xbd, - 0x04, 0xa9, 0xbd, 0x5a, 0xa4, 0x9f, 0x0d, 0x70, 0xf2, 0x97, 0x5e, 0x8a, 0x34, 0x0f, 0xc2, 0x28, - 0x01, 0x61, 0x16, 0x40, 0x2c, 0x4a, 0xbf, 0x04, 0x88, 0x6a, 0x09, 0x08, 0x6b, 0xb5, 0x20, 0x7e, - 0x19, 0xb0, 0x9d, 0x5c, 0xd9, 0xbe, 0x10, 0x78, 0x30, 0x0c, 0x48, 0x78, 0x7e, 0x08, 0xd7, 0x60, - 0xd3, 0x63, 0xcf, 0xd8, 0x00, 0xfb, 0x49, 0x12, 0x55, 0x68, 0xb6, 0x5b, 0x74, 0xca, 0x6e, 0x15, - 0x8c, 0x7c, 0x41, 0x5f, 0x61, 0x31, 0x54, 0x12, 0x6d, 0x77, 0xea, 0x40, 0xb7, 0xc0, 0x1e, 0xb2, - 0x58, 0xf4, 0xc3, 0x13, 0xa6, 0x34, 0x36, 0x7a, 0x5b, 0x1a, 0xe4, 0x91, 0x76, 0xbb, 0x59, 0x00, - 0x3a, 0x3c, 0x53, 0x7e, 0x37, 0x0a, 0xe5, 0x57, 0xd4, 0xf2, 0x7f, 0x95, 0xde, 0x17, 0x03, 0xb6, - 0x93, 0xda, 0xf8, 0x0b, 0xe2, 0x79, 0x5a, 0xe6, 0x79, 0x68, 0x55, 0x0b, 0xb4, 0xe6, 0x9d, 0x63, - 0x09, 0x5a, 0x56, 0x09, 0xad, 0xda, 0x6a, 0x69, 0x7d, 0xaa, 0x80, 0x9d, 0x4a, 0x52, 0x5f, 0x2e, - 0x1f, 0x8b, 0x13, 0xc6, 0x03, 0xbd, 0x3a, 0xb3, 0xe5, 0xe9, 0x58, 0xfc, 0x76, 0x12, 0xa5, 0x39, - 0xb4, 0x25, 0x7b, 0x9f, 0x04, 0xa1, 0xfb, 0xb5, 0x1a, 0x2b, 0xd2, 0x91, 0x7e, 0x65, 0x06, 0x8d, - 0x64, 0x65, 0xd2, 0x90, 0x0a, 0x8a, 0x05, 0xe3, 0x5a, 0xdc, 0xd4, 0xd1, 0xf9, 0x59, 0x81, 0xad, - 0xa7, 0x24, 0x24, 0x9c, 0x0e, 0x5c, 0x12, 0x47, 0x2c, 0x8c, 0x09, 0xba, 0x07, 0x35, 0x4e, 0xe2, - 0x91, 0x2f, 0xd4, 0x39, 0x1a, 0xbd, 0xcb, 0x1a, 0xe8, 0x4c, 0x5c, 0xd7, 0x55, 0x41, 0x47, 0x6b, - 0xae, 0x0e, 0x47, 0x77, 0xc1, 0x22, 0x9c, 0x33, 0xae, 0x4e, 0xd9, 0xe8, 0xed, 0x2e, 0x58, 0x77, - 0x28, 0x63, 0x8e, 0xd6, 0xdc, 0x24, 0xb8, 0xd5, 0x81, 0x5a, 0x92, 0x09, 0x39, 0x50, 0x0f, 0x48, - 0x1c, 0xe3, 0x0f, 0x44, 0x13, 0x48, 0xcd, 0xd6, 0x23, 0xb0, 0xd4, 0x2a, 0xa9, 0x78, 0xc0, 0xbc, - 0x74, 0x5e, 0x8d, 0x67, 0xbb, 0xbd, 0x71, 0xa6, 0xdb, 0x3f, 0xae, 0x83, 0xc5, 0x49, 0xe4, 0x4f, - 0x7a, 0xdf, 0x4c, 0xa8, 0x1e, 0xb0, 0xc1, 0x29, 0xda, 0x87, 0x8d, 0x7c, 0x33, 0x47, 0x17, 0x17, - 0xfc, 0x13, 0x68, 0xed, 0xcc, 0x17, 0xd1, 0x59, 0x93, 0x29, 0xf2, 0x6d, 0x30, 0x4b, 0x31, 0xfb, - 0xbd, 0x2d, 0x49, 0xf1, 0x3a, 0xed, 0x4f, 0xc5, 0x4e, 0x8a, 0xae, 0xfe, 0xe1, 0x7b, 0x53, 0x9e, - 0x72, 0x5e, 0x73, 0xce, 0x52, 0x2e, 0xea, 0xdc, 0x25, 0x29, 0xfb, 0xe9, 0x7f, 0xc8, 0xe9, 0x5b, - 0x42, 0x97, 0x4a, 0x5a, 0x52, 0x79, 0xaa, 0xd9, 0x67, 0x99, 0xa5, 0x9a, 0xf7, 0x5e, 0x17, 0xa7, - 0x3a, 0xae, 0xa9, 0x89, 0x3b, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x7c, 0xfb, 0xe9, 0xde, 0xf6, - 0x0a, 0x00, 0x00, + // 802 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x57, 0xdf, 0x6e, 0xd3, 0x3e, + 0x14, 0x5e, 0x93, 0xa6, 0xcd, 0x4e, 0xb7, 0xdf, 0x2a, 0x6b, 0xda, 0x2f, 0x2a, 0x03, 0xaa, 0x0a, + 0xa4, 0x01, 0xa2, 0x17, 0x05, 0x09, 0x04, 0xe2, 0x62, 0xb0, 0x8a, 0x55, 0xe2, 0x6f, 0x40, 0x5c, + 0x70, 0xe7, 0x35, 0x1e, 0xb5, 0x96, 0xc6, 0x91, 0xe3, 0x56, 0x94, 0x2b, 0xae, 0xb8, 0xe1, 0x51, + 0x78, 0x0b, 0x9e, 0x80, 0x6b, 0x9e, 0x01, 0x89, 0x57, 0x40, 0x76, 0xd2, 0x34, 0xc9, 0x5a, 0xd3, + 0x89, 0x22, 0xed, 0x82, 0xab, 0xfa, 0x1c, 0x1f, 0x7f, 0xf6, 0xf7, 0xf9, 0x9c, 0xe3, 0x14, 0xc0, + 0x63, 0xfd, 0x93, 0x76, 0xc8, 0x99, 0x60, 0xc8, 0x52, 0x3f, 0xad, 0xaf, 0x26, 0xd4, 0x1f, 0x71, + 0x82, 0x05, 0x79, 0xc3, 0xfc, 0xd1, 0x90, 0x3c, 0x0f, 0x45, 0x84, 0xfe, 0x03, 0x83, 0x7a, 0x4e, + 0xa9, 0x59, 0xda, 0x5b, 0x77, 0x0d, 0xea, 0x21, 0x04, 0xe5, 0x00, 0x0f, 0x89, 0x63, 0x28, 0x8f, + 0x1a, 0x4b, 0x5f, 0x44, 0x3f, 0x10, 0xc7, 0x6c, 0x96, 0xf6, 0x4c, 0x57, 0x8d, 0x51, 0x13, 0x6a, + 0x1e, 0x89, 0xfa, 0x9c, 0x86, 0x82, 0xb2, 0xc0, 0x29, 0xab, 0xf0, 0xac, 0x0b, 0x5d, 0x02, 0x88, + 0x02, 0x1c, 0x46, 0x03, 0x26, 0x7a, 0x9e, 0x63, 0xa9, 0x80, 0x8c, 0x07, 0x5d, 0x87, 0x3a, 0x1e, + 0x63, 0xea, 0xe3, 0x23, 0xea, 0x53, 0x31, 0x79, 0xcb, 0x02, 0xe2, 0x54, 0x54, 0xd4, 0x29, 0x3f, + 0xda, 0x85, 0xf5, 0x90, 0xb3, 0x63, 0xea, 0x93, 0x9e, 0xe7, 0x54, 0x55, 0xd0, 0xcc, 0x81, 0x76, + 0xa0, 0x12, 0x32, 0xe6, 0xf7, 0x3c, 0xc7, 0x56, 0x53, 0x89, 0x85, 0x1a, 0x60, 0xcb, 0xd1, 0x33, + 0xc9, 0x67, 0x5d, 0xcd, 0xa4, 0x36, 0xda, 0x07, 0x7b, 0x48, 0x04, 0xf6, 0xb0, 0xc0, 0x0e, 0x34, + 0xcd, 0xbd, 0x5a, 0xe7, 0x6a, 0xac, 0x56, 0xbb, 0x28, 0x51, 0xfb, 0x69, 0x12, 0xd7, 0x0d, 0x04, + 0x9f, 0xb8, 0xe9, 0x32, 0xb9, 0xad, 0x14, 0xb9, 0xe7, 0x39, 0xb5, 0x78, 0xdb, 0xd8, 0x92, 0xc4, + 0x3d, 0x4e, 0xc7, 0x84, 0xab, 0x8d, 0x37, 0x62, 0xe2, 0x33, 0x4f, 0xe3, 0x3e, 0x6c, 0xe6, 0x20, + 0x51, 0x1d, 0xcc, 0x13, 0x32, 0x49, 0x2e, 0x41, 0x0e, 0xd1, 0x36, 0x58, 0x63, 0xec, 0x8f, 0xa6, + 0xd7, 0x10, 0x1b, 0xf7, 0x8c, 0xbb, 0xa5, 0xd6, 0xf7, 0x12, 0xd4, 0x0f, 0x88, 0x4f, 0xb4, 0x97, + 0x98, 0x25, 0x67, 0xe4, 0xc8, 0x15, 0x97, 0x2e, 0x41, 0xce, 0xd4, 0x90, 0x2b, 0xaf, 0x96, 0x9c, + 0xcc, 0xd0, 0xee, 0x7b, 0x41, 0x02, 0xef, 0x5f, 0x86, 0x6a, 0x32, 0xb4, 0x28, 0xd1, 0xf9, 0xca, + 0xd0, 0x6f, 0x06, 0x38, 0xd9, 0x1a, 0x7a, 0x95, 0x08, 0xfa, 0x97, 0x2f, 0xb3, 0x01, 0xf6, 0x58, + 0xed, 0x97, 0x5e, 0x65, 0x6a, 0xa3, 0x5e, 0x46, 0xca, 0x8a, 0x92, 0xf2, 0xe6, 0x9c, 0x62, 0xcf, + 0x1e, 0x74, 0x09, 0x49, 0xab, 0x1a, 0x49, 0xed, 0xd5, 0x4a, 0xfa, 0xc9, 0x00, 0x27, 0x5b, 0xb9, + 0x5a, 0x49, 0xb3, 0x42, 0x18, 0x1a, 0x21, 0xcc, 0x9c, 0x10, 0x8b, 0xe0, 0x97, 0x10, 0xa2, 0xac, + 0x11, 0xc2, 0x5a, 0xad, 0x10, 0x3f, 0x0d, 0xd8, 0x8e, 0xaf, 0x6c, 0x5f, 0x08, 0xdc, 0x1f, 0x0c, + 0x49, 0x70, 0x76, 0x11, 0xae, 0xc0, 0xa6, 0xc7, 0x9e, 0xb0, 0x3e, 0xf6, 0x63, 0x10, 0x95, 0x68, + 0xb6, 0x9b, 0x77, 0xca, 0x82, 0x1e, 0x8e, 0x7c, 0x41, 0x5f, 0x60, 0x31, 0x50, 0x14, 0x6d, 0x77, + 0xe6, 0x40, 0x37, 0xc0, 0x1e, 0xb0, 0x48, 0xf4, 0x82, 0x63, 0xa6, 0x38, 0xd6, 0x3a, 0x5b, 0x89, + 0x90, 0x87, 0x89, 0xdb, 0x4d, 0x03, 0x50, 0xf7, 0x54, 0xfa, 0x5d, 0xcb, 0xa5, 0x5f, 0x9e, 0xcb, + 0xf9, 0x4a, 0xbd, 0x2f, 0x06, 0x6c, 0xc7, 0xb9, 0xf1, 0x07, 0x8a, 0x67, 0xd5, 0x32, 0xcf, 0xa2, + 0x56, 0x39, 0xa7, 0xd6, 0xbc, 0x73, 0x2c, 0xa1, 0x96, 0xa5, 0x51, 0xab, 0xb2, 0x5a, 0xb5, 0x3e, + 0x96, 0xc0, 0x9e, 0x52, 0x52, 0xcd, 0xdd, 0xc7, 0xe2, 0x98, 0xf1, 0x61, 0xb2, 0x3a, 0xb5, 0xe5, + 0xe9, 0x58, 0xf4, 0x7a, 0x12, 0x4e, 0x31, 0x12, 0x4b, 0xf6, 0x3e, 0x29, 0x44, 0xf2, 0xe8, 0xaa, + 0xb1, 0x52, 0x3a, 0x4c, 0xaa, 0xcc, 0xa0, 0xa1, 0xcc, 0x4c, 0x1a, 0x50, 0x41, 0xb1, 0x60, 0x3c, + 0x21, 0x37, 0x73, 0xb4, 0x7e, 0x94, 0x60, 0xeb, 0x31, 0x09, 0x08, 0xa7, 0x7d, 0x97, 0x44, 0x21, + 0x0b, 0x22, 0x82, 0xee, 0x40, 0x85, 0x93, 0x68, 0xe4, 0x0b, 0x75, 0x8e, 0x5a, 0xe7, 0x62, 0x22, + 0x68, 0x21, 0xae, 0xed, 0xaa, 0xa0, 0xc3, 0x35, 0x37, 0x09, 0x47, 0xb7, 0xc1, 0x22, 0x9c, 0x33, + 0xae, 0x4e, 0x59, 0xeb, 0xec, 0x2e, 0x58, 0xd7, 0x95, 0x31, 0x87, 0x6b, 0x6e, 0x1c, 0xdc, 0x68, + 0x41, 0x25, 0x46, 0x42, 0x0e, 0x54, 0x87, 0x24, 0x8a, 0xf0, 0x3b, 0x92, 0x28, 0x30, 0x35, 0x1b, + 0x0f, 0xc0, 0x52, 0xab, 0x24, 0xe3, 0x3e, 0xf3, 0xa6, 0xf3, 0x6a, 0x5c, 0xec, 0xf6, 0xc6, 0xa9, + 0x6e, 0xff, 0xb0, 0x0a, 0x16, 0x27, 0xa1, 0x3f, 0xe9, 0x7c, 0x2e, 0x43, 0xf9, 0x80, 0xf5, 0x4f, + 0xd0, 0x3e, 0x6c, 0x64, 0x9b, 0x39, 0xfa, 0x7f, 0xc1, 0xe7, 0x5c, 0x63, 0x67, 0x3e, 0x89, 0xd6, + 0x9a, 0x84, 0xc8, 0xb6, 0xc1, 0x14, 0xa2, 0xf8, 0xd1, 0xa4, 0x87, 0xc8, 0xbe, 0xce, 0x29, 0x44, + 0xf1, 0xc9, 0xd6, 0x40, 0xbc, 0x9c, 0xb6, 0xb8, 0x7c, 0x33, 0x46, 0x97, 0x7f, 0xf3, 0x64, 0xe9, + 0x21, 0xe7, 0xf5, 0xf7, 0x14, 0x72, 0x51, 0xf3, 0xd7, 0x40, 0xf6, 0xa6, 0xff, 0x25, 0x66, 0xe5, + 0x88, 0x2e, 0x68, 0xba, 0x9a, 0x1e, 0xaa, 0x58, 0xd9, 0x29, 0xd4, 0xbc, 0x92, 0x5f, 0x0c, 0x75, + 0x54, 0x51, 0x13, 0xb7, 0x7e, 0x05, 0x00, 0x00, 0xff, 0xff, 0x35, 0x7a, 0x69, 0x6c, 0xfe, 0x0c, + 0x00, 0x00, } diff --git a/pkg/dock/proto/dock.proto b/pkg/dock/proto/dock.proto index 57302052f..89c0aac2c 100755 --- a/pkg/dock/proto/dock.proto +++ b/pkg/dock/proto/dock.proto @@ -35,22 +35,25 @@ package proto; service Dock { // Create a volume rpc CreateVolume (CreateVolumeOpts) returns (GenericResponse){} - + // Delete a volume rpc DeleteVolume (DeleteVolumeOpts) returns (GenericResponse){} - + + // Extend a volume + rpc ExtendVolume (ExtendVolumeOpts) returns (GenericResponse){} + // Create a volume snapshot rpc CreateVolumeSnapshot (CreateVolumeSnapshotOpts) - returns (GenericResponse){} - + returns (GenericResponse){} + // Delete a volume snapshot rpc DeleteVolumeSnapshot (DeleteVolumeSnapshotOpts) - returns (GenericResponse){} - + returns (GenericResponse){} + // Create a volume attachment rpc CreateAttachment (CreateAttachmentOpts) returns (GenericResponse){} - - // Delete a volume attachment + + // Delete a volume attachment rpc DeleteAttachment (DeleteAttachmentOpts) returns (GenericResponse){} } @@ -74,13 +77,13 @@ message CreateVolumeOpts { // The uuid of the pool on which volume will be created, required. string poolId = 8; // The name of the pool on which volume will be created, required. - string poolName = 9; + string poolName = 9; // The metadata of the volume, optional. map metadata = 10; - // The dock infomation on which the request will be executed - string dockId = 11; - // The storage driver type. - string driverName = 12; + // The dock infomation on which the request will be executed + string dockId = 11; + // The storage driver type. + string driverName = 12; } // DeleteVolumeOpts is a structure which indicates all required properties @@ -90,10 +93,39 @@ message DeleteVolumeOpts { string id = 1; // The metadata of the volume, optional. map metadata = 2; - // The dock infomation on which the request will be executed. - string dockId = 3; - // The storage driver type. - string driverName = 4; + // The dock infomation on which the request will be executed. + string dockId = 3; + // The storage driver type. + string driverName = 4; +} + +// ExtendVolumeOpts is a structure which indicates all required properties +// for Extending a volume. +message ExtendVolumeOpts { + // The uuid of the volume, optional when creating. + string id = 1; + // The name of the volume, required. + string name = 2; + // The requested capacity of the volume, required. + int64 size = 3; + // The description of the volume, optional. + string description = 4; + // When create volume from snapshot, this field is required. + string snapshotId = 5; + // The locality that volume belongs to, required. + string availabilityZone = 6; + // The service level that volume belongs to, required. + string profileId = 7; + // The uuid of the pool on which volume will be created, required. + string poolId = 8; + // The name of the pool on which volume will be created, required. + string poolName = 9; + // The metadata of the volume, optional. + map metadata = 10; + // The dock infomation on which the request will be executed + string dockId = 11; + // The storage driver type. + string driverName = 12; } // CreateVolumeSnapshotOpts is a structure which indicates all required @@ -111,10 +143,10 @@ message CreateVolumeSnapshotOpts { string volumeId = 5; // The metadata of the volume snapshot, optional. map metadata = 6; - // The dock infomation on which the request will be executed - string dockId = 7; - // The storage driver type. - string driverName = 8; + // The dock infomation on which the request will be executed + string dockId = 7; + // The storage driver type. + string driverName = 8; } // DeleteVolumeSnapshotOpts is a structure which indicates all required @@ -126,10 +158,10 @@ message DeleteVolumeSnapshotOpts { string volumeId = 2; // The metadata of the volume snapshot, optional. map metadata = 3; - // The dock infomation on which the request will be executed - string dockId = 4; - // The storage driver type. - string driverName = 5; + // The dock infomation on which the request will be executed + string dockId = 4; + // The storage driver type. + string driverName = 5; } // CreateAttachmentOpts is a structure which indicates all required @@ -147,10 +179,10 @@ message CreateAttachmentOpts { HostInfo hostInfo = 5; // The metadata of the volume attachment, optional. map metadata = 6; - // The dock infomation on which the request will be executed - string dockId = 7; - // The storage driver type. - string driverName = 8; + // The dock infomation on which the request will be executed + string dockId = 7; + // The storage driver type. + string driverName = 8; } // DeleteAttachmentOpts is a structure which indicates all required @@ -164,10 +196,10 @@ message DeleteAttachmentOpts { HostInfo hostInfo = 3; // The metadata of the volume attachment, optional. map metadata = 4; - // The dock infomation on which the request will be executed - string dockId = 5; - // The storage driver type. - string driverName = 6; + // The dock infomation on which the request will be executed + string dockId = 5; + // The storage driver type. + string driverName = 6; } message HostInfo { @@ -190,13 +222,13 @@ message HostInfo { message GenericResponse { message Result { string message = 1; - } - + } + message Error { string code = 1; string description = 2; } - + oneof reply { Result result = 1; Error error = 2; diff --git a/pkg/dock/server/server.go b/pkg/dock/server/server.go index 61fde6396..82f9fa98a 100755 --- a/pkg/dock/server/server.go +++ b/pkg/dock/server/server.go @@ -107,6 +107,24 @@ func (ds *dockServer) DeleteVolume(ctx context.Context, opt *pb.DeleteVolumeOpts return &res, nil } +// ExtendVolume implements opensds.DockServer +func (ds *dockServer) ExtendVolume(ctx context.Context, opt *pb.ExtendVolumeOpts) (*pb.GenericResponse, error) { + var res pb.GenericResponse + + log.Info("Dock server receive extend volume request, vr =", opt) + + vol, err := dock.Brain.ExtendVolume(opt) + if err != nil { + log.Error("When extend volume in dock module:", err) + + res.Reply = GenericResponseError("400", fmt.Sprint(err)) + return &res, err + } + + res.Reply = GenericResponseResult(vol) + return &res, nil +} + // CreateAttachment implements opensds.DockServer func (ds *dockServer) CreateAttachment(ctx context.Context, opt *pb.CreateAttachmentOpts) (*pb.GenericResponse, error) { var res pb.GenericResponse diff --git a/pkg/model/volume.go b/pkg/model/volume.go index e673e0107..e5e5f693a 100755 --- a/pkg/model/volume.go +++ b/pkg/model/volume.go @@ -155,3 +155,13 @@ type VolumeSnapshotSpec struct { // +optional Metadata map[string]string `json:"metadata,omitempty"` } + +// ExtendSpec ... +type ExtendSpec struct { + NewSize int64 `json:"newSize,omitempty"` +} + +// ExtendVolumeSpec ... +type ExtendVolumeSpec struct { + Extend ExtendSpec `json:"extend,omitempty"` +} diff --git a/pkg/utils/config/config.go b/pkg/utils/config/config.go index a015f27f1..27bf4bce8 100755 --- a/pkg/utils/config/config.go +++ b/pkg/utils/config/config.go @@ -129,7 +129,6 @@ func parseItems(section string, v reflect.Value, cfg *ini.File) { if err == nil { strVal = key.Value() } - log.Warningf("Get key(%s.%s) failed, using default key(%s).", section, tags[ConfKeyName], strVal) } switch field.Kind() { case reflect.Bool: diff --git a/pkg/utils/urls/urls.go b/pkg/utils/urls/urls.go index c9e73ee3c..490d32073 100644 --- a/pkg/utils/urls/urls.go +++ b/pkg/utils/urls/urls.go @@ -34,6 +34,11 @@ func GenerateVolumeURL(in ...string) string { return generateURL("block/volumes", in...) } +// GenerateNewVolumeURL ... +func GenerateNewVolumeURL(in ...string) string { + return generateURL("volumes", in...) +} + func GenerateAttachmentURL(in ...string) string { return generateURL("block/attachments", in...) } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 2e901e010..207f2df46 100755 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -15,8 +15,11 @@ package utils import ( + "fmt" "os" "reflect" + + log "github.com/golang/glog" ) func Contained(obj, target interface{}) bool { @@ -68,3 +71,16 @@ func PathExists(path string) (bool, error) { } return false, err } + +func Retry(retryNum int, desc string, fn func() error) error { + for i := 0; i < retryNum; i++ { + if err := fn(); err != nil { + log.Errorf("%s:%s, retry %d time(s)", desc, err, i+1) + } else { + return nil + } + } + err := fmt.Errorf("%s retry exceed the max retry times(%d).", desc, retryNum) + log.Error(err) + return err +} diff --git a/script/CI/test b/script/CI/test index d70bc00ed..714ab3ed2 100755 --- a/script/CI/test +++ b/script/CI/test @@ -1,9 +1,47 @@ #!/bin/bash +# Copyright 2017 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. + +# Keep track of the script directory +TOP_DIR=$(cd $(dirname "$0") && pwd) +# OpenSDS Root directory +OPENSDS_DIR=$(cd $TOP_DIR/../.. && pwd) + +split_line(){ + echo "================================================================================================" + echo $* + echo "================================================================================================" +} + # Start unit test. +split_line "Start unit test" go test -v github.com/opensds/opensds/osdsctl/... -cover go test -v github.com/opensds/opensds/client/... -cover go test -v github.com/opensds/opensds/pkg/... -cover go test -v github.com/opensds/opensds/contrib/... -cover + # Start integration test. +split_line "Start integration test" +sudo $OPENSDS_DIR/test/integration/prepare.sh go test -v github.com/opensds/opensds/test/integration/... -tags integration +sudo killall -9 osdslet osdsdock +sudo rm /etc/opensds/opensds.conf -rf + +# Start lvm e2e test +split_line "Start lvm e2e test" +sudo $OPENSDS_DIR/script/devsds/install.sh -b lvm +ps -ef|grep osds +go test -v github.com/opensds/opensds/test/e2e/... -tags e2e +sudo $OPENSDS_DIR/script/devsds/uninstall.sh diff --git a/script/cluster/bootstrap.sh b/script/cluster/bootstrap.sh index 1e2546648..3828186d4 100755 --- a/script/cluster/bootstrap.sh +++ b/script/cluster/bootstrap.sh @@ -17,43 +17,67 @@ # This script helps new contributors or users set up their local workstation # for opensds installation and development. -OPENSDS_DIR=${HOME}/gopath/src/github.com/opensds -OPENSDS_ROOT=${OPENSDS_DIR}/opensds -ETCD_URL=https://github.com/coreos/etcd/releases/download/v3.2.0 -ETCD_TARBALL=etcd-v3.2.0-linux-amd64.tar.gz -ETCD_DIR=etcd-v3.2.0-linux-amd64 - -# Run apt-get update to update the system packages. -sudo apt-get update -source /etc/profile +# Temporary directory +OPT_DIR=/opt/opensds +mkdir -p $OPT_DIR + +# Golang version +GOLANG_VERSION=${GOLANG_VERSION:-1.9.2} +GOENV_PROFILE=${GOENV_PROFILE:-/etc/profile.d/goenv.sh} + +# Log file +LOG_DIR=/var/log/opensds +LOGFILE=${LOGFILE:-/var/log/opensds/bootstrap.log} +mkdir -p $LOG_DIR + +# Log function +log() { + DATE=`date "+%Y-%m-%d %H:%M:%S"` + USER=$(whoami) + echo "${DATE} [INFO] $@" + echo "${DATE} ${USER} execute $0 [INFO] $@" > $LOGFILE +} +log_error () +{ + DATE=`date "+%Y-%m-%d %H:%M:%S"` + USER=$(whoami) + echo "${DATE} [ERROR] $@" 2>&1 + echo "${DATE} ${USER} execute $0 [ERROR] $@" > $LOGFILE +} +log OpenSDS bootstrap starting ... + +# load profile +source /etc/profile # Install Golang environment if ! which go &>/dev/null; then - wget https://storage.googleapis.com/golang/go1.9.2.linux-amd64.tar.gz - tar xzf go1.9.linux-amd64.tar.gz -C /usr/local/ - echo 'export GOROOT=/usr/local/go' >> /etc/profile - echo 'export GOPATH=$HOME/gopath' >> /etc/profile - echo 'export PATH=$PATH:$GOROOT/bin:$GOPATH/bin' >> /etc/profile + log "Golang is not exist, downloading..." + wget https://storage.googleapis.com/golang/go${GOLANG_VERSION}.linux-amd64.tar.gz -O $OPT_DIR/go${GOLANG_VERSION}.linux-amd64.tar.gz > /dev/null + log "tar xzf $OPT_DIR/go${GOLANG_VERSION}.linux-amd64.tar.gz -C /usr/local/" + tar xzf $OPT_DIR/go${GOLANG_VERSION}.linux-amd64.tar.gz -C /usr/local/ + echo 'export GOROOT=/usr/local/go' > $GOENV_PROFILE + echo 'export GOPATH=$HOME/gopath' >> $GOENV_PROFILE + echo 'export PATH=$PATH:$GOROOT/bin:$GOPATH/bin' >> $GOENV_PROFILE + source $GOENV_PROFILE fi -# If etcd file not exists, download it from etcd release url. -if [ ! -d ${HOME}/${ETCD_DIR} ]; then - curl -L ${ETCD_URL}/${ETCD_TARBALL} -o ${HOME}/${ETCD_TARBALL} - cd ${HOME} - tar xzf ${HOME}/${ETCD_TARBALL} -fi +GOPATH=${GOPATH:-$HOME/gopath} +OPENSDS_ROOT=${GOPATH}/src/github.com/opensds +OPENSDS_DIR=${GOPATH}/src/github.com/opensds/opensds +mkdir -p ${OPENSDS_ROOT} -# OpenSDS Download and Build -if [ ! -d $OPENSDS_DIR ]; then - mkdir -p ${OPENSDS_DIR} -fi -cd ${OPENSDS_DIR} -if [ ! -d $OPENSDS_ROOT ]; then +cd ${OPENSDS_ROOT} +if [ ! -d ${OPENSDS_DIR} ]; then + log "Download the OpenSDS source code." git clone https://github.com/opensds/opensds.git -b master fi -cd ${OPENSDS_ROOT} -if [ ! -d $OPENSDS_ROOT/build ]; then - sudo apt-get install librados-dev librbd-dev -y + +cd ${OPENSDS_DIR} +if [ ! -d ${OPENSDS_DIR}/build ]; then + sudo apt-get update > /dev/null + sudo apt-get install librados-dev librbd-dev -y > /dev/null + log "Build OpenSDS ..." make fi +log OpenSDS bootstrapped successfully. you can execute 'source /etc/profile' to load golang ENV. diff --git a/script/devsds/install.sh b/script/devsds/install.sh index 394afe926..22357c3f1 100755 --- a/script/devsds/install.sh +++ b/script/devsds/install.sh @@ -166,8 +166,8 @@ done # Run osdsdock and osdslet daemon in background. ( cd ${OPENSDS_DIR} -sudo build/out/bin/osdslet -daemon -sudo build/out/bin/osdsdock -daemon +sudo build/out/bin/osdslet --daemon --alsologtostderr +sudo build/out/bin/osdsdock --daemon --alsologtostderr osds::echo_summary "Waiting for osdslet to come up." osds::util::wait_for_url localhost:50040 "osdslet" 0.25 80 diff --git a/script/devsds/lib/lvm.sh b/script/devsds/lib/lvm.sh index 43b8cb6c2..419ba4442 100755 --- a/script/devsds/lib/lvm.sh +++ b/script/devsds/lib/lvm.sh @@ -87,6 +87,7 @@ osds::lvm::init() { # Remove volumes that already exist. osds::lvm::remove_volumes $vg osds::lvm::set_configuration + osds::lvm::set_lvm_filter } osds::lvm::remove_volumes() { @@ -129,6 +130,38 @@ osds::lvm::clean_volume_group() { osds::lvm::cleanup(){ osds::lvm::clean_volume_group $DEFAULT_VOLUME_GROUP_NAME + osds::lvm::clean_lvm_filter +} + +# osds::lvm::clean_lvm_filter() Remove the filter rule set in set_lvm_filter() + +osds::lvm::clean_lvm_filter() { + sudo sed -i "s/^.*# from devsds$//" /etc/lvm/lvm.conf +} + +# osds::lvm::set_lvm_filter() Gather all devices configured for LVM and +# use them to build a global device filter +# osds::lvm::set_lvm_filter() Create a device filter +# and add to /etc/lvm.conf. Note this uses +# all current PV's in use by LVM on the +# system to build it's filter. +osds::lvm::set_lvm_filter() { + local filter_suffix='"r|.*|" ] # from devsds' + local filter_string="global_filter = [ " + local pv + local vg + local line + + for pv_info in $(sudo pvs --noheadings -o name); do + pv=$(echo -e "${pv_info}" | sed 's/ //g' | sed 's/\/dev\///g') + new="\"a|$pv|\", " + filter_string=$filter_string$new + done + filter_string=$filter_string$filter_suffix + + osds::lvm::clean_lvm_filter + sudo sed -i "/# global_filter = \[.*\]/a\ $global_filter$filter_string" /etc/lvm/lvm.conf + osds::echo_summary "set lvm.conf device global_filter to: $filter_string" } # Restore xtrace diff --git a/test/e2e/ceph_start.sh b/test/e2e/ceph_start.sh deleted file mode 100755 index 01c5a5331..000000000 --- a/test/e2e/ceph_start.sh +++ /dev/null @@ -1,111 +0,0 @@ -#!/bin/bash - -# Copyright 2017 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. - -OPENSDS_DIR=${GOPATH}/src/github.com/opensds -OPENSDS_ROOT=${OPENSDS_DIR}/opensds -OPENSDS_LOG_DIR=/var/log/opensds -OPENSDS_CONFIG_DIR=/etc/opensds/driver -ETCD_DIR=etcd-v3.2.0-linux-amd64 - -function log() { -DATE=`date "+%Y-%m-%d %H:%M:%S"` -USER=$(whoami) -echo "${DATE} ${USER} execute $0 [INFO] $@" -} - -function log_error () -{ -DATE=`date "+%Y-%m-%d %H:%M:%S"` -USER=$(whoami) -echo "${DATE} ${USER} execute $0 [ERROR] $@" 2>&1 -} - -function cleanup(){ - rm ${HOME}/${ETCD_DIR}/default.etcd -rf - killall osdslet osdsdock etcd &>/dev/null -} - -# OpenSDS cluster installation. -cd ${OPENSDS_ROOT} && script/cluster/bootstrap.sh - -# Import some pre-defined environment variables. -source /etc/profile - -[ ! -d $OPENSDS_CONFIG_DIR ] && mkdir -p ${OPENSDS_CONFIG_DIR} -[ ! -d $OPENSDS_LOG_DIR ] && mkdir -p ${OPENSDS_LOG_DIR} - -# Config backend info. -cat > /etc/opensds/opensds.conf << OPENSDS_GLOABL_CONFIG_DOC -[osdslet] -api_endpoint = localhost:50040 -graceful = True -log_file = $OPENSDS_LOG_DIR/osdslet.log -socket_order = inc - -[osdsdock] -api_endpoint = localhost:50050 -log_file = $OPENSDS_LOG_DIR/osdsdock.log -# Specify which backends should be enabled, sample,ceph,cinder,lvm and so on. -enabled_backends = ceph - -[ceph] -name = ceph -description = Ceph E2E Test -driver_name = ceph -config_path = $OPENSDS_CONFIG_DIR/ceph.yaml - -[database] -endpoint = localhost:2379,localhost:2380 -driver = etcd -OPENSDS_GLOABL_CONFIG_DOC - -cat > ${OPENSDS_CONFIG_DIR}/ceph.yaml <>${OPENSDS_LOG_DIR}/etcd.log & -# Waiting for the etcd up. -n=1 -export ETCDCTL_API=3 -while ! ./etcdctl endpoint status &>/dev/null -do - echo try $n times - let n++ - if [ $n -ge 10 ]; then - log_error "The etcd is not up exited" - cleanup - exit 1 - fi - sleep 1 -done - - -# Run osdsdock and osdslet daemon in background. -cd ${OPENSDS_ROOT} -sudo build/out/bin/osdsdock -daemon -sudo build/out/bin/osdslet -daemon - -# Start e2e test. -go test -v github.com/opensds/opensds/test/e2e/... -tags e2e - -cleanup -exit 0 diff --git a/test/e2e/cinder_start.sh b/test/e2e/cinder_start.sh deleted file mode 100755 index 2505881c6..000000000 --- a/test/e2e/cinder_start.sh +++ /dev/null @@ -1,124 +0,0 @@ -#!/bin/bash - -# Copyright 2017 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. - -OPENSDS_DIR=${HOME}/gopath/src/github.com/opensds -OPENSDS_ROOT=${OPENSDS_DIR}/opensds -OPENSDS_LOG_DIR=/var/log/opensds -OPENSDS_CONFIG_DIR=/etc/opensds/driver -OPENSTACK_OPENRC=/home/devstack/openrc -ETCD_DIR=etcd-v3.2.0-linux-amd64 - -if [[ -n "$1" ]]; then - OPENSTACK_OPENRC=$1 -fi - -function log() { -DATE=`date "+%Y-%m-%d %H:%M:%S"` -USER=$(whoami) -echo "${DATE} ${USER} execute $0 [INFO] $@" -} - -function log_error () -{ -DATE=`date "+%Y-%m-%d %H:%M:%S"` -USER=$(whoami) -echo "${DATE} ${USER} execute $0 [ERROR] $@" 2>&1 -} - -function cleanup(){ - rm ${HOME}/${ETCD_DIR}/default.etcd -rf - killall osdslet osdsdock etcd &>/dev/null -} - -# OpenSDS cluster installation. -cd ${OPENSDS_ROOT} && script/cluster/bootstrap.sh - -# Import some pre-defined environment variables. -source /etc/profile - -[ ! -d $OPENSDS_CONFIG_DIR ] && mkdir -p ${OPENSDS_CONFIG_DIR} -[ ! -d $OPENSDS_LOG_DIR ] && mkdir -p ${OPENSDS_LOG_DIR} - -# Config backend info. -cat > /etc/opensds/opensds.conf << OPENSDS_GLOABL_CONFIG_DOC -[osdslet] -api_endpoint = localhost:50040 -graceful = True -log_file = $OPENSDS_LOG_DIR/osdslet.log -socket_order = inc - -[osdsdock] -api_endpoint = localhost:50050 -log_file = $OPENSDS_LOG_DIR/osdsdock.log -# Specify which backends should be enabled, sample,ceph,cinder,lvm and so on. -enabled_backends = cinder - -[cinder] -name = cinder -description = Cinder E2E Test -driver_name = cinder -config_path = $OPENSDS_CONFIG_DIR/cinder.yaml - -[database] -endpoint = localhost:2379,localhost:2380 -driver = etcd -OPENSDS_GLOABL_CONFIG_DOC - - -source $OPENSTACK_OPENRC >/dev/null -POOL_NAME=`cinder get-pools| grep -v "^+"| sed -n '2p' | tr -d "|" | awk '{print $2}'` -cat > ${OPENSDS_CONFIG_DIR}/cinder.yaml <>${OPENSDS_LOG_DIR}/etcd.log & -# Waiting for the etcd up. -n=1 -export ETCDCTL_API=3 -while ! ./etcdctl endpoint status &>/dev/null -do - echo try $n times - let n++ - if [ $n -ge 10 ]; then - log_error "The etcd is not up exited" - cleanup - exit 1 - fi - sleep 1 -done - - -# Run osdsdock and osdslet daemon in background. -cd ${OPENSDS_ROOT} -sudo build/out/bin/osdsdock -daemon -sudo build/out/bin/osdslet -daemon - -# Start e2e test. -go test -v github.com/opensds/opensds/test/e2e/... -tags e2e - -cleanup -exit 0 diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 5af292f35..036e79b46 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -127,6 +127,53 @@ func TestListVolumes(t *testing.T) { t.Log("Check all volumes success, got", string(volsBody)) } +func TestUpdateVolume(t *testing.T) { + vol, err := prepareVolume(t) + if err != nil { + t.Error("Failed to run volume prepare function:", err) + return + } + + t.Log("Start updating volume...") + var body = &model.VolumeSpec{ + Name: "Update Volume Name", + Description: "Update Volume Description", + } + + newVol, err := c.UpdateVolume(vol.Id, body) + if err != nil { + t.Error("update volume failed:", err) + return + } + + newVolBody, _ := json.MarshalIndent(newVol, "", " ") + cleanVolumeIfFailedOrFinished(t, newVol.Id) + t.Log("Update volume success, got:", string(newVolBody)) +} + +func TestExtendVolume(t *testing.T) { + vol, err := prepareVolume(t) + if err != nil { + t.Error("Failed to run volume prepare function:", err) + return + } + + t.Log("Start extending volume...") + body := &model.ExtendVolumeSpec{ + Extend: model.ExtendSpec{NewSize: int64(vol.Size + 1)}, + } + + newVol, err := c.ExtendVolume(vol.Id, body) + if err != nil { + t.Error("extend volume failed:", err) + return + } + + newVolBody, _ := json.MarshalIndent(newVol, "", " ") + cleanVolumeIfFailedOrFinished(t, newVol.Id) + t.Log("Extend volume success, got:", string(newVolBody)) +} + func TestDeleteVolume(t *testing.T) { vol, err := prepareVolume(t) if err != nil { @@ -142,6 +189,7 @@ func TestDeleteVolume(t *testing.T) { t.Log("Delete volume success!") } +/* func TestCreateVolumeAttachment(t *testing.T) { vol, err := prepareVolume(t) if err != nil { @@ -231,6 +279,7 @@ func TestDeleteVolumeAttachment(t *testing.T) { } t.Log("Delete volume attachment success!") } +*/ func TestCreateVolumeSnapshot(t *testing.T) { vol, err := prepareVolume(t) @@ -321,6 +370,30 @@ func TestDeleteVolumeSnapshot(t *testing.T) { t.Log("Delete volume snapshot success!") } +func TestUpdateVolumeSnapshot(t *testing.T) { + snp, err := prepareVolumeSnapshot(t) + if err != nil { + t.Error("Failed to run volume snapshot prepare function:", err) + return + } + defer cleanVolumeAndSnapshotIfFailedOrFinished(t, snp.VolumeId, snp.Id) + + t.Log("Start updating volume snapshot...") + var body = &model.VolumeSnapshotSpec{ + Name: "Update Volume Snapshot Name", + Description: "Update Volume Snapshot Description", + } + + newSnp, err := c.UpdateVolumeSnapshot(snp.Id, body) + if err != nil { + t.Error("update volume snapshot failed:", err) + return + } + + newSnpBody, _ := json.MarshalIndent(newSnp, "", " ") + t.Log("Update volume snapshot success, got:", string(newSnpBody)) +} + func prepareVolume(t *testing.T) (*model.VolumeSpec, error) { t.Log("Start preparing volume...") var body = &model.VolumeSpec{ diff --git a/test/e2e/lvm_start.sh b/test/e2e/lvm_start.sh deleted file mode 100755 index d0a295416..000000000 --- a/test/e2e/lvm_start.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/bin/bash - -# Copyright 2017 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. - -OPENSDS_DIR=${GOPATH}/src/github.com/opensds -OPENSDS_ROOT=${OPENSDS_DIR}/opensds -OPENSDS_LOG_DIR=/var/log/opensds -OPENSDS_CONFIG_DIR=/etc/opensds/driver -ETCD_DIR=etcd-v3.2.0-linux-amd64 -VG_NAME=vg001 -TGT_BINDIP=127.0.0.1 - -function log() { -DATE=`date "+%Y-%m-%d %H:%M:%S"` -USER=$(whoami) -echo "${DATE} ${USER} execute $0 [INFO] $@" -} - -function log_error() { -DATE=`date "+%Y-%m-%d %H:%M:%S"` -USER=$(whoami) -echo "${DATE} ${USER} execute $0 [ERROR] $@" 2>&1 -} - -function cleanup() { - rm ${HOME}/${ETCD_DIR}/default.etcd -rf - killall osdslet osdsdock etcd &>/dev/null -} - -# OpenSDS cluster installation. -cd ${OPENSDS_ROOT} && script/cluster/bootstrap.sh - -# Import some pre-defined environment variables. -source /etc/profile - -[ ! -d $OPENSDS_CONFIG_DIR ] && mkdir -p ${OPENSDS_CONFIG_DIR} -[ ! -d $OPENSDS_LOG_DIR ] && mkdir -p ${OPENSDS_LOG_DIR} - -# Config backend info. -cat > /etc/opensds/opensds.conf << OPENSDS_GLOABL_CONFIG_DOC -[osdslet] -api_endpoint = localhost:50040 -graceful = True -log_file = $OPENSDS_LOG_DIR/osdslet.log -socket_order = inc - -[osdsdock] -api_endpoint = localhost:50050 -log_file = $OPENSDS_LOG_DIR/osdsdock.log -# Specify which backends should be enabled, sample,ceph,cinder,lvm and so on. -enabled_backends = lvm - -[lvm] -name = lvm -description = LVM E2E Test -driver_name = lvm -config_path = $OPENSDS_CONFIG_DIR/lvm.yaml - -[database] -endpoint = localhost:2379,localhost:2380 -driver = etcd -OPENSDS_GLOABL_CONFIG_DOC - -cat > ${OPENSDS_CONFIG_DIR}/lvm.yaml <>${OPENSDS_LOG_DIR}/etcd.log & -# Waiting for the etcd up. -n=1 -export ETCDCTL_API=3 -while ! ./etcdctl endpoint status &>/dev/null -do - echo try $n times - let n++ - if [ $n -ge 10 ]; then - log_error "The etcd is not up exited" - cleanup - exit 1 - fi - sleep 1 -done - - -# Run osdsdock and osdslet daemon in background. -cd ${OPENSDS_ROOT} -sudo build/out/bin/osdsdock -daemon -sudo build/out/bin/osdslet -daemon - -# Start e2e test. -go test -v github.com/opensds/opensds/test/e2e/... -tags e2e - -cleanup -exit 0 diff --git a/test/integration/client_test.go b/test/integration/client_test.go index 29f06ef48..c474a236d 100755 --- a/test/integration/client_test.go +++ b/test/integration/client_test.go @@ -222,6 +222,46 @@ func TestClientDeleteVolume(t *testing.T) { t.Log("Delete volume success!") } +func TestClientUpdateVolume(t *testing.T) { + var volID = "bd5b12a8-a101-11e7-941e-d77981b584d8" + body := &model.VolumeSpec{ + Name: "sample-volume", + Description: "This is a sample volume for testing", + } + + vol, err := c.UpdateVolume(volID, body) + if err != nil { + t.Error("update volume in client failed:", err) + return + } + + volBody, _ := json.MarshalIndent(vol, "", " ") + t.Log(string(volBody)) +} + +func TestClientExtendVolume(t *testing.T) { + var volID = "bd5b12a8-a101-11e7-941e-d77981b584d8" + oldVol, err := c.GetVolume(volID) + + if err != nil { + t.Error("get volume in client failed:", err) + return + } + + body := &model.ExtendVolumeSpec{ + Extend: model.ExtendSpec{NewSize: int64(oldVol.Size + 1)}, + } + vol, err := c.ExtendVolume(volID, body) + + if err != nil { + t.Error("extend volume in client failed:", err) + return + } + + volBody, _ := json.MarshalIndent(vol, "", " ") + t.Log(string(volBody)) +} + func TestClientCreateVolumeAttachment(t *testing.T) { var body = &model.VolumeAttachmentSpec{ VolumeId: "bd5b12a8-a101-11e7-941e-d77981b584d8", @@ -331,3 +371,20 @@ func TestClientDeleteVolumeSnapshot(t *testing.T) { t.Log("Delete volume snapshot success!") } + +func TestClientUpdateVolumeSnapshot(t *testing.T) { + var snpID = "3769855c-a102-11e7-b772-17b880d2f537" + body := &model.VolumeSnapshotSpec{ + Name: "sample-snapshot-01", + Description: "This is the first sample snapshot for testing", + } + + snp, err := c.UpdateVolumeSnapshot(snpID, body) + if err != nil { + t.Error("update volume snapshot in client failed:", err) + return + } + + snpBody, _ := json.MarshalIndent(snp, "", " ") + t.Log(string(snpBody)) +} diff --git a/test/integration/controller_test.go b/test/integration/controller_test.go index 7a6bec18d..fc52c92db 100755 --- a/test/integration/controller_test.go +++ b/test/integration/controller_test.go @@ -54,6 +54,19 @@ func TestControllerDeleteVolume(t *testing.T) { } } +func TestControllerExtendVolume(t *testing.T) { + vc.SetDock(dckInfo) + + vol, err := vc.ExtendVolume(&pb.ExtendVolumeOpts{}) + if err != nil { + t.Error("extend volume in controller failed:", err) + return + } + + volBody, _ := json.MarshalIndent(vol, "", " ") + t.Log(string(volBody)) +} + func TestControllerCreateVolumeAttachment(t *testing.T) { vc.SetDock(dckInfo) diff --git a/test/integration/prepare.sh b/test/integration/prepare.sh index 459d44c19..3cb1d75a0 100755 --- a/test/integration/prepare.sh +++ b/test/integration/prepare.sh @@ -14,38 +14,39 @@ # See the License for the specific language governing permissions and # limitations under the License. -OPENSDS_DIR=${HOME}/gopath/src/github.com/opensds -OPENSDS_ROOT=${OPENSDS_DIR}/opensds +# Keep track of the script directory +TOP_DIR=$(cd $(dirname "$0") && pwd) + +# OpenSDS Root directory +OPENSDS_DIR=$(cd $TOP_DIR/../.. && pwd) OPENSDS_CONF=/etc/opensds/opensds.conf # Config backend info. -if [ ! -f ${OPENSDS_CONF} ]; then - mkdir -p /etc/opensds - echo ' - [osdslet] - api_endpoint = localhost:50040 - graceful = True - log_file = /var/log/opensds/osdslet.log - socket_order = inc - - [osdsdock] - api_endpoint = localhost:50050 - log_file = /var/log/opensds/osdsdock.log - # Enabled backend types, such as sample, ceph, cinder, etc. - enabled_backends = sample - - [sample] - name = sample - description = Sample backend for testing - driver_name = default - - [database] - # Enabled database types, such as etcd, mysql, fake, etc. - driver = fake - ' >> ${OPENSDS_CONF} -fi +mkdir -p /etc/opensds +cat > ${OPENSDS_CONF} << OPENSDS_GLOBAL_CONFIG_DOC +[osdslet] +api_endpoint = localhost:50040 +graceful = True +log_file = /var/log/opensds/osdslet.log +socket_order = inc + +[osdsdock] +api_endpoint = localhost:50050 +log_file = /var/log/opensds/osdsdock.log +# Enabled backend types, such as sample, ceph, cinder, etc. +enabled_backends = sample + +[sample] +name = sample +description = Sample backend for testing +driver_name = default + +[database] +# Enabled database types, such as etcd, mysql, fake, etc. +driver = fake +OPENSDS_GLOBAL_CONFIG_DOC # Run osdsdock and osdslet daemon in background. -cd ${OPENSDS_ROOT} -sudo build/out/bin/osdsdock -daemon -sudo build/out/bin/osdslet -daemon +cd ${OPENSDS_DIR} +sudo ${OPENSDS_DIR}/build/out/bin/osdsdock -daemon +sudo ${OPENSDS_DIR}/build/out/bin/osdslet -daemon diff --git a/testutils/db/fake.go b/testutils/db/fake.go index ed3d029ed..a12d43e09 100755 --- a/testutils/db/fake.go +++ b/testutils/db/fake.go @@ -197,7 +197,7 @@ func (fc *FakeDbClient) ListVolumes() ([]*model.VolumeSpec, error) { } // UpdateVolume -func (fc *FakeDbClient) UpdateVolume(volID string, vol *model.VolumeSpec) (*model.VolumeSpec, error) { +func (fc *FakeDbClient) UpdateVolume(vol *model.VolumeSpec) (*model.VolumeSpec, error) { return &SampleVolumes[0], nil } @@ -206,6 +206,11 @@ func (fc *FakeDbClient) DeleteVolume(volID string) error { return nil } +// ExtendVolume ... +func (fc *FakeDbClient) ExtendVolume(vol *model.VolumeSpec) (*model.VolumeSpec, error) { + return &SampleVolumes[0], nil +} + // CreateVolumeAttachment func (fc *FakeDbClient) CreateVolumeAttachment(attachment *model.VolumeAttachmentSpec) (*model.VolumeAttachmentSpec, error) { return &SampleAttachments[0], nil diff --git a/testutils/db/testing/mock_db.go b/testutils/db/testing/mock_db.go index 4fbc321d0..4f94ab2df 100755 --- a/testutils/db/testing/mock_db.go +++ b/testutils/db/testing/mock_db.go @@ -697,13 +697,13 @@ func (_m *MockClient) UpdateProfile(prfID string, input *model.ProfileSpec) (*mo return r0, r1 } -// UpdateVolume -func (_m *MockClient) UpdateVolume(volID string, vol *model.VolumeSpec) (*model.VolumeSpec, error) { - ret := _m.Called(volID, vol) +// UpdateVolume ... +func (_m *MockClient) UpdateVolume(vol *model.VolumeSpec) (*model.VolumeSpec, error) { + ret := _m.Called(vol.Id, vol) var r0 *model.VolumeSpec if rf, ok := ret.Get(0).(func(string, *model.VolumeSpec) *model.VolumeSpec); ok { - r0 = rf(volID, vol) + r0 = rf(vol.Id, vol) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*model.VolumeSpec) @@ -712,7 +712,7 @@ func (_m *MockClient) UpdateVolume(volID string, vol *model.VolumeSpec) (*model. var r1 error if rf, ok := ret.Get(1).(func(string, *model.VolumeSpec) error); ok { - r1 = rf(volID, vol) + r1 = rf(vol.Id, vol) } else { r1 = ret.Error(1) } @@ -720,13 +720,13 @@ func (_m *MockClient) UpdateVolume(volID string, vol *model.VolumeSpec) (*model. return r0, r1 } -// UpdateVolumeAttachment -func (_m *MockClient) UpdateVolumeAttachment(attachmentId string, attachment *model.VolumeAttachmentSpec) (*model.VolumeAttachmentSpec, error) { - ret := _m.Called(attachmentId, attachment) +// UpdateVolumeAttachment ... +func (_m *MockClient) UpdateVolumeAttachment(attachmentID string, attachment *model.VolumeAttachmentSpec) (*model.VolumeAttachmentSpec, error) { + ret := _m.Called(attachmentID, attachment) var r0 *model.VolumeAttachmentSpec if rf, ok := ret.Get(0).(func(string, *model.VolumeAttachmentSpec) *model.VolumeAttachmentSpec); ok { - r0 = rf(attachmentId, attachment) + r0 = rf(attachmentID, attachment) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*model.VolumeAttachmentSpec) @@ -735,7 +735,7 @@ func (_m *MockClient) UpdateVolumeAttachment(attachmentId string, attachment *mo var r1 error if rf, ok := ret.Get(1).(func(string, *model.VolumeAttachmentSpec) error); ok { - r1 = rf(attachmentId, attachment) + r1 = rf(attachmentID, attachment) } else { r1 = ret.Error(1) } @@ -743,7 +743,7 @@ func (_m *MockClient) UpdateVolumeAttachment(attachmentId string, attachment *mo return r0, r1 } -// UpdateVolumeSnapshot +// UpdateVolumeSnapshot ... func (_m *MockClient) UpdateVolumeSnapshot(snapshotID string, vs *model.VolumeSnapshotSpec) (*model.VolumeSnapshotSpec, error) { ret := _m.Called(snapshotID, vs) @@ -765,3 +765,26 @@ func (_m *MockClient) UpdateVolumeSnapshot(snapshotID string, vs *model.VolumeSn return r0, r1 } + +// ExtendVolume ... +func (_m *MockClient) ExtendVolume(vol *model.VolumeSpec) (*model.VolumeSpec, error) { + ret := _m.Called(vol.Id, vol) + + var r0 *model.VolumeSpec + if rf, ok := ret.Get(0).(func(string, *model.VolumeSpec) *model.VolumeSpec); ok { + r0 = rf(vol.Id, vol) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*model.VolumeSpec) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, *model.VolumeSpec) error); ok { + r1 = rf(vol.Id, vol) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/testutils/driver/sample.go b/testutils/driver/sample.go index 0ee643495..71657f00a 100644 --- a/testutils/driver/sample.go +++ b/testutils/driver/sample.go @@ -58,6 +58,11 @@ func (*Driver) DeleteVolume(opt *pb.DeleteVolumeOpts) error { return nil } +// ExtendVolume ... +func (*Driver) ExtendVolume(opt *pb.ExtendVolumeOpts) (*model.VolumeSpec, error) { + return &SampleVolumes[0], nil +} + // InitializeConnection func (*Driver) InitializeConnection(opt *pb.CreateAttachmentOpts) (*model.ConnectionInfo, error) { return &SampleConnection, nil