diff --git a/internal/rbd/group_controller.go b/internal/rbd/group_controller.go new file mode 100644 index 000000000000..5fcecc638b8e --- /dev/null +++ b/internal/rbd/group_controller.go @@ -0,0 +1,209 @@ +/* +Copyright 2024 The Ceph-CSI Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package rbd + +import ( + "context" + "errors" + + "github.com/container-storage-interface/spec/lib/go/csi" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/ceph/ceph-csi/internal/rbd_group" + types "github.com/ceph/ceph-csi/internal/rbd_types" + "github.com/ceph/ceph-csi/internal/util" +) + +// cephConfig contains the configuration parameters for the Ceph cluster. +type cephConfig struct { + clusterID string + mons string + pool string + journalPool string + namespace string +} + +func getCephConfig(ctx context.Context, params, secrets map[string]string) (*cephConfig, error) { + clusterID, err := util.GetClusterID(params) + if err != nil { + return nil, err + } + + mons, _, err := util.GetMonsAndClusterID(ctx, clusterID, false) + if err != nil { + return nil, err + } + + pool := params["pool"] + if pool == "" { + return nil, errors.New("missing required parameter: pool") + } + + journalPool := params["journalPool"] + if journalPool == "" { + journalPool = pool + } + + namespace := params["radosNamespace"] + if namespace == "" { + return nil, errors.New("missing required parameter: radosNamespace") + } + + return &cephConfig{ + clusterID: clusterID, + mons: mons, + pool: pool, + journalPool: journalPool, + namespace: namespace, + }, nil +} + +func (cs *ControllerServer) GroupControllerGetCapabilities(context.Context, *csi.GroupControllerGetCapabilitiesRequest) (*csi.GroupControllerGetCapabilitiesResponse, error) { + return &csi.GroupControllerGetCapabilitiesResponse{ + Capabilities: []*csi.GroupControllerServiceCapability{{ + Type: &csi.GroupControllerServiceCapability_Rpc{ + Rpc: &csi.GroupControllerServiceCapability_RPC{ + Type: csi.GroupControllerServiceCapability_RPC_CREATE_DELETE_GET_VOLUME_GROUP_SNAPSHOT, + }, + }, + }}, + }, nil +} + +func getVolumesForGroup(ctx context.Context, volumeIDs []string, secrets map[string]string) ([]types.Volume, error) { + creds, err := util.NewUserCredentials(secrets) + if err != nil { + return nil, err + } + defer creds.DeleteCredentials() + + volumes := make([]types.Volume, len(volumeIDs)) + for i, id := range volumeIDs { + volume, err := GenVolFromVolID(ctx, id, creds, secrets) + if err != nil { + return nil, err + } + + volumes[i] = volume + } + + return volumes, nil +} + +func (cs *ControllerServer) CreateVolumeGroupSnapshot(ctx context.Context, req *csi.CreateVolumeGroupSnapshotRequest) (*csi.CreateVolumeGroupSnapshotResponse, error) { + + // 1. resolve each rbd-image from the volume-id + // 2. create a RBDVolumeGroup + // 3. add each rbd-image to the RBDVolumeGroup + // 4. create a GroupSnapshot + // 5. remove all rbd-images from the RBDVolumeGroup + // 6. return the RBDVolumeGroup-name and list of snapshots + + config, err := getCephConfig(ctx, req.GetParameters(), req.GetSecrets()) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + volumes, err := getVolumesForGroup(ctx, req.GetSourceVolumeIds(), req.GetSecrets()) + if err != nil { + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + group := rbd_group.NewVolumeGroup(ctx, req.GetName(), config.clusterID, req.GetSecrets()) + defer group.Destroy(ctx) + + err = group.SetMonitors(ctx, config.mons) + if err != nil { + return nil, status.Error(codes.Aborted, err.Error()) + } + + err = group.SetPool(ctx, config.pool) + if err != nil { + return nil, status.Error(codes.Aborted, err.Error()) + } + + err = group.SetJournalNamespace(ctx, config.journalPool, config.namespace) + if err != nil { + return nil, status.Error(codes.Aborted, err.Error()) + } + + // TODO: add images to the group + for _, volume := range volumes { + err = group.AddVolume(ctx, volume) + if err != nil { + return nil, status.Error(codes.Aborted, err.Error()) + } + } + + groupSnapshot, err := group.CreateSnapshot(ctx, req.GetName()) + if err != nil { + return nil, status.Error(codes.Aborted, err.Error()) + } + defer groupSnapshot.Destroy(ctx) + + groupSnapshotID, err := groupSnapshot.GetID(ctx) + if err != nil { + return nil, status.Error(codes.Aborted, err.Error()) + } + + snapshots, err := groupSnapshot.ListSnapshots(ctx) + if err != nil { + return nil, status.Error(codes.Aborted, err.Error()) + } + + csiSnapshots := make([]*csi.Snapshot, len(snapshots)) + for i, snapshot := range snapshots { + csiSnapshot, err := snapshot.ToCSISnapshot(ctx) + if err != nil { + return nil, status.Error(codes.Aborted, err.Error()) + } + + csiSnapshots[i] = csiSnapshot + } + + // TODO: remove images from the group + for _, volume := range volumes { + err = group.RemoveVolume(ctx, volume) + if err != nil { + return nil, status.Error(codes.Aborted, err.Error()) + } + } + + return &csi.CreateVolumeGroupSnapshotResponse{ + GroupSnapshot: &csi.VolumeGroupSnapshot{ + GroupSnapshotId: groupSnapshotID, + Snapshots: csiSnapshots, + CreationTime: nil, + ReadyToUse: groupSnapshot.GetReadyToUse(ctx), + }, + }, nil +} + +func (cs *ControllerServer) DeleteVolumeGroupSnapshot(ctx context.Context, req *csi.DeleteVolumeGroupSnapshotRequest) (*csi.DeleteVolumeGroupSnapshotResponse, error) { + + // 1. verify that all snapshots in the request are all snapshots in the group + // 2. delete the group + + return nil, nil +} + +// TODO +// sortof optional, only used for static/pre-provisioned VolumeGroupSnapshots +func (cs *ControllerServer) GetVolumeGroupSnapshot(ctx context.Context, req *csi.GetVolumeGroupSnapshotRequest) (*csi.GetVolumeGroupSnapshotResponse, error) { + return nil, nil +} diff --git a/internal/rbd/rbd_util.go b/internal/rbd/rbd_util.go index 1fbb79b0cee3..401711a9bf7d 100644 --- a/internal/rbd/rbd_util.go +++ b/internal/rbd/rbd_util.go @@ -84,10 +84,6 @@ const ( clusterNameKey = "csi.ceph.com/cluster/name" ) -type Image interface { - AddToGroup(groupName, ioctx *rados.IOContext) error -} - // rbdImage contains common attributes and methods for the rbdVolume and // rbdSnapshot types. type rbdImage struct { diff --git a/internal/rbd/volume.go b/internal/rbd/volume.go new file mode 100644 index 000000000000..400896920b05 --- /dev/null +++ b/internal/rbd/volume.go @@ -0,0 +1,35 @@ +package rbd + +import ( + "context" + + "github.com/ceph/go-ceph/rados" + librbd "github.com/ceph/go-ceph/rbd" + + types "github.com/ceph/ceph-csi/internal/rbd_types" +) + +///////////////////////////////////////////////////////////////////// +// // +// this is the implementation of the rbd_types.RBDVolume interface // +// // +///////////////////////////////////////////////////////////////////// + +// verify that the rbdImage type implements the RBDVolume interface +var _ types.Volume = &rbdImage{} + +func (ri *rbdImage) GetID(ctx context.Context) (string, error) { + return ri.VolID, nil +} + +// AddToGroup adds the image to the group with the ioctx. This is called from +// the rbd_group package, as that can pass the ioctx of the group. +func (ri *rbdImage) AddToGroup(ctx context.Context, ioctx *rados.IOContext, group string) error { + return librbd.GroupImageAdd(ioctx, group, ri.ioctx, ri.RbdImageName) +} + +// RemoveFromGroup removes the image to the group with the ioctx. This is +// called from the rbd_group package, as that can pass the ioctx of the group. +func (ri *rbdImage) RemoveFromGroup(ctx context.Context, ioctx *rados.IOContext, group string) error { + return librbd.GroupImageRemove(ioctx, group, ri.ioctx, ri.RbdImageName) +} diff --git a/internal/rbd_group/snapshot.go b/internal/rbd_group/snapshot.go new file mode 100644 index 000000000000..b80557bbb261 --- /dev/null +++ b/internal/rbd_group/snapshot.go @@ -0,0 +1,76 @@ +/* +Copyright 2024 The Ceph-CSI Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package rbd_group + +import ( + "context" + "fmt" + + "github.com/container-storage-interface/spec/lib/go/csi" + + types "github.com/ceph/ceph-csi/internal/rbd_types" +) + +// verify that rbdSnapshot type implements the Snapshot interface +var _ types.Snapshot = &rbdGroupSnapshot{} + +// rbdGroupSnapshot describes a single snapshot that was taken as part of a group. +type rbdGroupSnapshot struct { + parent types.Volume + snapName string + snapID uint64 // not needed now, may be used for cloning in the future + + // group is the optional value for a VolumeGroup that was used for + group types.VolumeGroup +} + +func newGroupSnapshot(group, name string, snapID uint64) types.Snapshot { + return &rbdGroupSnapshot{ + //groupName: group, + snapName: name, + snapID: snapID, + } +} + +func (rgs *rbdGroupSnapshot) Destroy(ctx context.Context) { + // nothing to do yet +} + +// String returns the image-spec of the snapshot. +func (rgs *rbdGroupSnapshot) String() string { + return fmt.Sprintf("%s@%s", rgs.parent, rgs.snapName) +} + +func (rgs *rbdGroupSnapshot) ToCSISnapshot(ctx context.Context) (*csi.Snapshot, error) { + parentID, err := rgs.parent.GetID(ctx) + if err != nil { + return nil, err + } + + return &csi.Snapshot{ + SizeBytes: 0, + SnapshotId: "", + SourceVolumeId: "", + CreationTime: nil, + ReadyToUse: false, + GroupSnapshotId: parentID, + }, nil +} + +func (rgs *rbdGroupSnapshot) Map(ctx context.Context) (string, error) { + return "/dev/rbd123", nil +} diff --git a/internal/rbd_group/volume_group.go b/internal/rbd_group/volume_group.go index fd13dc4962af..c55da8179cf8 100644 --- a/internal/rbd_group/volume_group.go +++ b/internal/rbd_group/volume_group.go @@ -1,45 +1,74 @@ +/* +Copyright 2024 The Ceph-CSI Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package rbd_group import ( "context" "errors" - "github.com/ceph/ceph-csi/internal/rbd" + "github.com/ceph/go-ceph/rados" + librbd "github.com/ceph/go-ceph/rbd" + + "github.com/ceph/ceph-csi/internal/journal" + types "github.com/ceph/ceph-csi/internal/rbd_types" "github.com/ceph/ceph-csi/internal/util" ) const ( - ErrRBDGroupNotConnected = errors.New("RBD group is not connected") + groupSuffix = "rbd-group" + groupPrefix = "rbd-group" ) -type RBDVolumeGroup interface { - Destroy() - - SetPool(pool string) - - Create(ctx context.Context) error - Delete(ctx context.Context) error - - AddVolume(ctx context.Context, volumeID string) error - RemoveVolume(ctx context.Context, volumeID string) error - - CreateSnapshot(ctx context.Context, name string) error -} +var ( + ErrRBDGroupNotConnected = errors.New("RBD group is not connected") +) type rbdVolumeGroup struct { name string + clusterID string credentials *util.Credentials - secrets []secrets - - images []*rbd.Image + secrets map[string]string + + monitors string + pool string + poolID int64 + conn *util.ClusterConnection + ioctx *rados.IOContext + journal journal.VolumeGroupJournal + journalPool string + + id string + volumes []types.Volume } -func NewRBDVolumeGroup(ctx context.Context, name string, cr *util.Credentials, secrets []string) RBDVolumeGroup { +// verify that rbdVolumeGroup implements the VolumeGroup interface +var _ types.VolumeGroup = &rbdVolumeGroup{} + +// NewVolumeGroup initializes a new VolumeGroup object that can be used +// to manage an `rbd group`. +func NewVolumeGroup(ctx context.Context, name, clusterID string, secrets map[string]string) types.VolumeGroup { + creds, _ := util.NewUserCredentials(secrets) + return &rbdVolumeGroup{ name: name, - credentials: cr, + clusterID: clusterID, + credentials: creds, secrets: secrets, - }, nil + } } func (rvg *rbdVolumeGroup) validate() error { @@ -47,17 +76,66 @@ func (rvg *rbdVolumeGroup) validate() error { return ErrRBDGroupNotConnected } + if rvg.journal == nil { + return ErrRBDGroupNotConnected + } + return nil } -func (rvg *rbdVolumeGroup) Destroy() { +// Destroy frees the resources used by the rbdVolumeGroup. +func (rvg *rbdVolumeGroup) Destroy(ctx context.Context) { if rvg.ioctx != nil { rvg.ioctx.Destroy() rvg.ioctx = nil } + + if rvg.conn != nil { + rvg.conn.Destroy() + rvg.conn = nil + } + + if rvg.journal != nil { + rvg.journal.Destroy() + rvg.journal = nil + } + + if rvg.credentials != nil { + rvg.credentials.DeleteCredentials() + rvg.credentials = nil + } +} + +func (rvg *rbdVolumeGroup) GetID(ctx context.Context) (string, error) { + // FIXME: this should be the group-snapshot-handle + if rvg.id != "" { + return rvg.id, nil + } + + return rvg.id, nil } -func (rvg *rbdVolumeGroup) SetPool(pool string) { +// SetMonitors connects to the Ceph cluster. +func (rvg *rbdVolumeGroup) SetMonitors(ctx context.Context, monitors string) error { + conn := &util.ClusterConnection{} + err := conn.Connect(monitors, rvg.credentials) + if err != nil { + return err + } + + rvg.conn = conn + rvg.monitors = monitors + + return nil +} + +// SetPool uses the connection to the Ceph cluster to create an IOContext to +// the pool. +func (rvg *rbdVolumeGroup) SetPool(ctx context.Context, pool string) error { + if rvg.conn == nil { + return ErrRBDGroupNotConnected + } + ioctx, err := rvg.conn.GetIoctx(pool) if err != nil { return err @@ -65,6 +143,26 @@ func (rvg *rbdVolumeGroup) SetPool(pool string) { rvg.pool = pool rvg.ioctx = ioctx + + return nil +} + +func (rvg *rbdVolumeGroup) SetJournalNamespace(ctx context.Context, pool, namespace string) error { + if rvg.conn == nil { + return ErrRBDGroupNotConnected + } + + vgj := journal.NewCSIVolumeGroupJournal(groupSuffix) + vgj.SetNamespace(namespace) + err := vgj.Connect(rvg.monitors, namespace, rvg.credentials) + if err != nil { + return err + } + + rvg.journal = vgj + rvg.journalPool = pool + + return nil } func (rvg *rbdVolumeGroup) Create(ctx context.Context) error { @@ -72,8 +170,31 @@ func (rvg *rbdVolumeGroup) Create(ctx context.Context) error { return err } + journalPoolID, poolID, err := util.GetPoolIDs( + ctx, + rvg.monitors, + rvg.journalPool, + rvg.pool, + rvg.credentials) + if err != nil { + return err + } + + id, uniqueName, err := rvg.journal.ReserveName( + ctx, + rvg.journalPool, + journalPoolID, + rvg.name, + groupPrefix) + if err != nil { + return err + } + + rvg.id = id + rvg.poolID = poolID + // TODO: if the group already exists, resolve details and use that - return rbd.GroupCreate(rvg.ioctx, rvg.name) + return librbd.GroupCreate(rvg.ioctx, uniqueName) } func (rvg *rbdVolumeGroup) Delete(ctx context.Context) error { @@ -81,37 +202,51 @@ func (rvg *rbdVolumeGroup) Delete(ctx context.Context) error { return err } - return rbd.GroupRemove(rvg.ioctx, rvg.name) + return librbd.GroupRemove(rvg.ioctx, rvg.name) } -func (rvg *rbdVolumeGroup) AddVolume(ctx context.Context, image rbd.Image) error { +func (rvg *rbdVolumeGroup) AddVolume(ctx context.Context, image types.Volume) error { if err := rvg.validate(); err != nil { return err } - return image.AddToGroup(rvg.name, rvg.ioctx) + return image.AddToGroup(ctx, rvg.ioctx, rvg.name) } -func (rvg *rbdVolumeGroup) RemoveVolume(ctx context.Context, volumeID string) error { +func (rvg *rbdVolumeGroup) RemoveVolume(ctx context.Context, image types.Volume) error { if err := rvg.validate(); err != nil { return err } - return rbd.GroupImageRemove(rvg.ioctx, group, rvg.ioctx, volumeID) + return image.RemoveFromGroup(ctx, rvg.ioctx, rvg.name) } -func (rvg *rbdVolumeGroup) CreateSnapshot(ctx context.Context, snapName string) error { +func (rvg *rbdVolumeGroup) CreateSnapshot(ctx context.Context, snapName string) (types.VolumeGroupSnapshot, error) { if err := rvg.validate(); err != nil { - return err + return nil, err + } + + err := librbd.GroupSnapCreate(rvg.ioctx, rvg.name, snapName) + if err != nil { + return nil, err } - return rbd.GroupSnapCreate(rvg.ioctx, rvg.group, snapName) + // TODO: if the snapName already exists, use that as return value + + return newVolumeGroupSnapshot(ctx, rvg, snapName), nil } -func (rvg *rbdVolumeGroup) ListSnapshots(ctx context.Context, snapName string) ([]Snapshot, error) { +func (rvg *rbdVolumeGroup) DeleteSnapshot(ctx context.Context, snapName string) error { if err := rvg.validate(); err != nil { - return nil, err + return err } - return nil, nil + err := librbd.GroupSnapRemove(rvg.ioctx, rvg.name, snapName) + if err != nil { + return err + } + + // TODO: it is not an error if the snapName was not found or does not exist + + return nil } diff --git a/internal/rbd_group/volume_group_snapshot.go b/internal/rbd_group/volume_group_snapshot.go new file mode 100644 index 000000000000..56bb3b8f53c7 --- /dev/null +++ b/internal/rbd_group/volume_group_snapshot.go @@ -0,0 +1,71 @@ +/* +Copyright 2024 The Ceph-CSI Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package rbd_group + +import ( + "context" + "time" + + types "github.com/ceph/ceph-csi/internal/rbd_types" +) + +// verify that rbdVolumeGroupSnapshot implements the VolumeGroupSnapshot interface +var _ types.VolumeGroupSnapshot = &rbdVolumeGroupSnapshot{} + +// rbdVolumeGroupSnapshot is a description of a group snapshot that was taken +// at some point in time. The rbd-group still exists, but there are no +// rbd-images in the group anymore. The list of snapshots that belongs to the +// group is stored in the journal. +type rbdVolumeGroupSnapshot struct { + parentGroup *rbdVolumeGroup + name string + + snapshots []types.Snapshot +} + +func newVolumeGroupSnapshot(ctx context.Context, parent *rbdVolumeGroup, name string) types.VolumeGroupSnapshot { + return &rbdVolumeGroupSnapshot{ + parentGroup: parent, + name: name, + } +} + +// Destroy frees the resources used by the rbdVolumeGroup. +func (rvgs *rbdVolumeGroupSnapshot) Destroy(ctx context.Context) { + // nothing to do (yet) +} + +func (rvgs *rbdVolumeGroupSnapshot) GetID(ctx context.Context) (string, error) { + // FIXME: this should be the group-snapshot-handle + return "", nil +} + +func (rvgs *rbdVolumeGroupSnapshot) ListSnapshots(ctx context.Context) ([]types.Snapshot, error) { + // TODO: use parent.journal to fetch the list of snapshots + return nil, nil +} + +func (rvgs *rbdVolumeGroupSnapshot) GetCreationTime(ctx context.Context) *time.Time { + // TODO: fetch the creation time of the group + // A group snapshot does not seem to have its own creation time. Use + // the time of the most recent created snapshot. + return nil +} + +func (rvgs *rbdVolumeGroupSnapshot) GetReadyToUse(ctx context.Context) bool { + return true +} diff --git a/internal/rbd_types/group.go b/internal/rbd_types/group.go new file mode 100644 index 000000000000..a837c5a4e51e --- /dev/null +++ b/internal/rbd_types/group.go @@ -0,0 +1,62 @@ +/* +Copyright 2024 The Ceph-CSI Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package rbd_types + +import ( + "context" + "time" +) + +// VolumeGroup contains a number of volumes, and can be used to create a +// VolumeGroupSnapshot. +type VolumeGroup interface { + // Destroy frees the resources used by the VolumeGroup. + Destroy(ctx context.Context) + + GetID(ctx context.Context) (string, error) + + // SetMonitors connects to the Ceph cluster. + SetMonitors(ctx context.Context, monitors string) error + // SetPool uses the connection to the Ceph cluster to create an + // IOContext to the pool. + SetPool(ctx context.Context, pool string) error + + SetJournalNamespace(ctx context.Context, pool, namespace string) error + + Create(ctx context.Context) error + Delete(ctx context.Context) error + + AddVolume(ctx context.Context, volume Volume) error + RemoveVolume(ctx context.Context, volume Volume) error + + CreateSnapshot(ctx context.Context, name string) (VolumeGroupSnapshot, error) + DeleteSnapshot(ctx context.Context, snapName string) error +} + +// VolumeGroupSnapshot is an instance of a group of snapshots that was taken +// from om a VolumeGroup. +type VolumeGroupSnapshot interface { + // Destroy frees the resources used by the VolumeGroupSnapshot. + Destroy(ctx context.Context) + + GetID(ctx context.Context) (string, error) + + ListSnapshots(ctx context.Context) ([]Snapshot, error) + + GetCreationTime(ctx context.Context) *time.Time + GetReadyToUse(ctx context.Context) bool +} diff --git a/internal/rbd_types/snapshot.go b/internal/rbd_types/snapshot.go new file mode 100644 index 000000000000..594c8722b4c8 --- /dev/null +++ b/internal/rbd_types/snapshot.go @@ -0,0 +1,33 @@ +/* +Copyright 2024 The Ceph-CSI Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package rbd_types + +import ( + "context" + + "github.com/container-storage-interface/spec/lib/go/csi" +) + +type Snapshot interface { + // Destroy frees the resources used by the Snapshot. + Destroy(ctx context.Context) + + ToCSISnapshot(ctx context.Context) (*csi.Snapshot, error) + + // Map the snapshot as an rbd device + Map(ctx context.Context) (string, error) // FIXME: just an example +} diff --git a/internal/rbd_types/volume.go b/internal/rbd_types/volume.go new file mode 100644 index 000000000000..580e8a59d6b7 --- /dev/null +++ b/internal/rbd_types/volume.go @@ -0,0 +1,33 @@ +/* +Copyright 2024 The Ceph-CSI Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package rbd_types + +import ( + "context" + + "github.com/ceph/go-ceph/rados" +) + +type Volume interface { + // Destroy frees the resources used by the Volume. + Destroy(/* TODO pass context.Context */) + + GetID(ctx context.Context) (string, error) + + AddToGroup(ctx context.Context, ioctx *rados.IOContext, group string) error + RemoveFromGroup(ctx context.Context, ioctx *rados.IOContext, group string) error +}