Skip to content

Commit 5111243

Browse files
committed
feat(lvm-driver): enable RAID support
Add support for LVM2 RAID types and parameters, with sane defaults for backwards compatibility. lvm-driver now assumes that a non- specified RAID type corresponds to the previous default of linear RAID, where data is packed onto disk until it runs out of space, continuing to the next as necessary. Tests have been added to cover the main supported RAID types (e.g. raid0, raid1, raid5, raid6, and raid10), but technically any valid LVM RAID type should work as well. Fixes #164 Signed-off-by: Nicholas Cioli <[email protected]>
1 parent 45ebdf6 commit 5111243

File tree

15 files changed

+504
-3
lines changed

15 files changed

+504
-3
lines changed

buildscripts/build.sh

+2-1
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,13 @@ output_name="bin/${PNAME}/"$GOOS"_"$GOARCH"/"$CTLNAME
9696
if [ $GOOS = "windows" ]; then
9797
output_name+='.exe'
9898
fi
99-
env GOOS=$GOOS GOARCH=$GOARCH go build -ldflags \
99+
env GOOS=$GOOS GOARCH=$GOARCH CGO_ENABLED=0 go build -ldflags \
100100
"-X github.com/openebs/lvm-localpv/pkg/version.GitCommit=${GIT_COMMIT} \
101101
-X main.CtlName='${CTLNAME}' \
102102
-X github.com/openebs/lvm-localpv/pkg/version.Version=${VERSION} \
103103
-X github.com/openebs/lvm-localpv/pkg/version.VersionMeta=${VERSION_META}"\
104104
-o $output_name\
105+
-installsuffix cgo \
105106
./cmd
106107

107108
echo ""

buildscripts/lvm-driver/Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
FROM alpine:3.14.8
15+
FROM alpine:3.17.5
1616
RUN apk add --no-cache lvm2 lvm2-extra util-linux device-mapper
1717
RUN apk add --no-cache btrfs-progs xfsprogs xfsprogs-extra e2fsprogs e2fsprogs-extra
1818
RUN apk add --no-cache ca-certificates libc6-compat
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
add support for LVM raid options

ci/ci-test.sh

+35
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ fi
3333
LVM_SYSTEMID="openebs-ci-test-system"
3434
LVM_CONFIG="global{system_id_source=lvmlocal}local{system_id=${LVM_SYSTEMID}}"
3535

36+
# RAID info for corresponding tests
37+
RAID_COUNT=5
38+
3639
# Clean up generated resources for successive tests.
3740
cleanup_loopdev() {
3841
sudo losetup -l | grep '(deleted)' | awk '{print $1}' \
@@ -60,13 +63,28 @@ cleanup_foreign_lvmvg() {
6063
cleanup_loopdev
6164
}
6265

66+
cleanup_raidvg() {
67+
sudo vgremove raidvg -y || true
68+
69+
for IMG in `seq ${RAID_COUNT}`
70+
do
71+
if [ -f /tmp/openebs_ci_raid_disk_${IMG}.img ]
72+
then
73+
rm /tmp/openebs_ci_raid_disk_${IMG}.img
74+
fi
75+
done
76+
77+
cleanup_loopdev
78+
}
79+
6380
cleanup() {
6481
set +e
6582

6683
echo "Cleaning up test resources"
6784

6885
cleanup_lvmvg
6986
cleanup_foreign_lvmvg
87+
cleanup_raidvg
7088

7189
kubectl delete pvc -n openebs lvmpv-pvc
7290
kubectl delete -f "${SNAP_CLASS}"
@@ -93,10 +111,27 @@ foreign_disk="$(sudo losetup -f /tmp/openebs_ci_foreign_disk.img --show)"
93111
sudo pvcreate "${foreign_disk}"
94112
sudo vgcreate foreign_lvmvg "${foreign_disk}" --systemid="${LVM_SYSTEMID}"
95113

114+
# setup a RAID volume group
115+
cleanup_raidvg
116+
raid_disks=()
117+
for IMG in `seq ${RAID_COUNT}`
118+
do
119+
truncate -s 1024G /tmp/openebs_ci_raid_disk_${IMG}.img
120+
raid_disk="$(sudo losetup -f /tmp/openebs_ci_raid_disk_${IMG}.img --show)"
121+
sudo pvcreate "${raid_disk}"
122+
123+
raid_disks+=("${raid_disk}")
124+
done
125+
sudo vgcreate raidvg "${raid_disks[@]}"
126+
96127
# install snapshot and thin volume module for lvm
97128
sudo modprobe dm-snapshot
98129
sudo modprobe dm_thin_pool
99130

131+
# install RAID modules for lvm
132+
sudo modprobe dm_raid
133+
sudo modprobe dm_integrity
134+
100135
# Prepare env for running BDD tests
101136
# Minikube is already running
102137
kubectl apply -f "${LVM_OPERATOR}"

deploy/lvm-operator.yaml

+48
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,47 @@ spec:
9595
description: Capacity of the volume
9696
minLength: 1
9797
type: string
98+
integrity:
99+
description: Integrity specifies whether logical volumes should be
100+
checked for integrity. If it is set to "yes", then the LVM LocalPV
101+
Driver will enable DM integrity for the logical volume
102+
enum:
103+
- "yes"
104+
- "no"
105+
type: string
106+
lvcreateoptions:
107+
description: LvCreateOptions are extra options for creating a volume.
108+
Options should be separated by ; e.g. "--vdo;--readahead;auto"
109+
type: string
110+
mirrors:
111+
description: Mirrors specifies the mirror count for a RAID configuration.
112+
minimum: 0
113+
type: integer
114+
nosync:
115+
description: NoSync enables the `--nosync` option of a RAID volume.
116+
If it is set to "yes", then LVM will skip drive sync when creating
117+
the mirrors. Defaults to "no"
118+
enum:
119+
- "yes"
120+
- "no"
121+
type: string
98122
ownerNodeID:
99123
description: OwnerNodeID is the Node ID where the volume group is
100124
present which is where the volume has been provisioned. OwnerNodeID
101125
can not be edited after the volume has been provisioned.
102126
minLength: 1
103127
type: string
128+
raidtype:
129+
description: RaidType specifies the type of RAID for the logical volume.
130+
Defaults to linear, if unspecified.
131+
enum:
132+
- linear
133+
- raid0
134+
- raid1
135+
- raid5
136+
- raid6
137+
- raid10
138+
type: string
104139
shared:
105140
description: Shared specifies whether the volume can be shared among
106141
multiple pods. If it is not set to "yes", then the LVM LocalPV Driver
@@ -109,6 +144,18 @@ spec:
109144
- "yes"
110145
- "no"
111146
type: string
147+
stripecount:
148+
description: StripeCount specifies the stripe count for a RAID configuration.
149+
This is equal to the number of physical volumes to scatter the logical
150+
volume
151+
minimum: 0
152+
type: integer
153+
stripesize:
154+
description: StripeSize specifies the size of a stripe for a RAID
155+
configuration. Must be a power of 2 but must not exceed the physical
156+
extent size
157+
minimum: 0
158+
type: integer
112159
thinProvision:
113160
description: ThinProvision specifies whether logical volumes can be
114161
thinly provisioned. If it is set to "yes", then the LVM LocalPV
@@ -129,6 +176,7 @@ spec:
129176
required:
130177
- capacity
131178
- ownerNodeID
179+
- raidtype
132180
- vgPattern
133181
- volGroup
134182
type: object

deploy/yamls/lvmvolume-crd.yaml

+48
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,47 @@ spec:
7474
description: Capacity of the volume
7575
minLength: 1
7676
type: string
77+
integrity:
78+
description: Integrity specifies whether logical volumes should be
79+
checked for integrity. If it is set to "yes", then the LVM LocalPV
80+
Driver will enable DM integrity for the logical volume
81+
enum:
82+
- "yes"
83+
- "no"
84+
type: string
85+
lvcreateoptions:
86+
description: LvCreateOptions are extra options for creating a volume.
87+
Options should be separated by ; e.g. "--vdo;--readahead;auto"
88+
type: string
89+
mirrors:
90+
description: Mirrors specifies the mirror count for a RAID configuration.
91+
minimum: 0
92+
type: integer
93+
nosync:
94+
description: NoSync enables the `--nosync` option of a RAID volume.
95+
If it is set to "yes", then LVM will skip drive sync when creating
96+
the mirrors. Defaults to "no"
97+
enum:
98+
- "yes"
99+
- "no"
100+
type: string
77101
ownerNodeID:
78102
description: OwnerNodeID is the Node ID where the volume group is
79103
present which is where the volume has been provisioned. OwnerNodeID
80104
can not be edited after the volume has been provisioned.
81105
minLength: 1
82106
type: string
107+
raidtype:
108+
description: RaidType specifies the type of RAID for the logical volume.
109+
Defaults to linear, if unspecified.
110+
enum:
111+
- linear
112+
- raid0
113+
- raid1
114+
- raid5
115+
- raid6
116+
- raid10
117+
type: string
83118
shared:
84119
description: Shared specifies whether the volume can be shared among
85120
multiple pods. If it is not set to "yes", then the LVM LocalPV Driver
@@ -88,6 +123,18 @@ spec:
88123
- "yes"
89124
- "no"
90125
type: string
126+
stripecount:
127+
description: StripeCount specifies the stripe count for a RAID configuration.
128+
This is equal to the number of physical volumes to scatter the logical
129+
volume
130+
minimum: 0
131+
type: integer
132+
stripesize:
133+
description: StripeSize specifies the size of a stripe for a RAID
134+
configuration. Must be a power of 2 but must not exceed the physical
135+
extent size
136+
minimum: 0
137+
type: integer
91138
thinProvision:
92139
description: ThinProvision specifies whether logical volumes can be
93140
thinly provisioned. If it is set to "yes", then the LVM LocalPV
@@ -108,6 +155,7 @@ spec:
108155
required:
109156
- capacity
110157
- ownerNodeID
158+
- raidtype
111159
- vgPattern
112160
- volGroup
113161
type: object

pkg/apis/openebs.io/lvm/v1alpha1/lvmvolume.go

+49
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,55 @@ type VolumeInfo struct {
8787
// +kubebuilder:validation:Required
8888
// +kubebuilder:validation:Enum=yes;no
8989
ThinProvision string `json:"thinProvision,omitempty"`
90+
91+
// RaidType specifies the type of RAID for the logical volume.
92+
// Defaults to linear, if unspecified.
93+
// +kubebuilder:validation:Required
94+
// +kubebuilder:validation:default=linear
95+
// +kubebuilder:validation:Enum=linear;raid0;raid1;raid5;raid6;raid10
96+
RaidType string `json:"raidtype"`
97+
98+
// Integrity specifies whether logical volumes should be checked for integrity.
99+
// If it is set to "yes", then the LVM LocalPV Driver will enable DM integrity
100+
// for the logical volume
101+
// +kubebuilder:validation:Required
102+
// +kubebuilder:validation:Enum=yes;no
103+
Integrity string `json:"integrity,omitempty"`
104+
105+
// Mirrors specifies the mirror count for a RAID configuration.
106+
// +kubebuilder:validation:Required
107+
// +kubebuilder:validation:default=0
108+
// +kubebuilder:validation:Minimum=0
109+
Mirrors uint `json:"mirrors,omitempty"`
110+
111+
// NoSync enables the `--nosync` option of a RAID volume.
112+
// If it is set to "yes", then LVM will skip drive sync when creating
113+
// the mirrors. Defaults to "no"
114+
// +kubebuilder:validation:Required
115+
// +kubebuilder:validation:default=no
116+
// +kubebuilder:validation:Enum=yes;no
117+
NoSync string `json:"nosync,omitempty"`
118+
119+
// StripeCount specifies the stripe count for a RAID configuration.
120+
// This is equal to the number of physical volumes to scatter the
121+
// logical volume
122+
// +kubebuilder:validation:Required
123+
// +kubebuilder:validation:default=0
124+
// +kubebuilder:validation:Minimum=0
125+
StripeCount uint `json:"stripecount,omitempty"`
126+
127+
// StripeSize specifies the size of a stripe for a RAID configuration.
128+
// Must be a power of 2 but must not exceed the physical extent size
129+
// +kubebuilder:validation:Required
130+
// +kubebuilder:validation:default=0
131+
// +kubebuilder:validation:Minimum=0
132+
StripeSize uint `json:"stripesize,omitempty"`
133+
134+
// LvCreateOptions are extra options for creating a volume.
135+
// Options should be separated by ;
136+
// e.g. "--vdo;--readahead;auto"
137+
// +kubebuilder:validation:Required
138+
LvCreateOptions string `json:"lvcreateoptions,omitempty"`
90139
}
91140

92141
// VolStatus string that specifies the current state of the volume provisioning request.

pkg/builder/volbuilder/volume.go

+82
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ limitations under the License.
1717
package volbuilder
1818

1919
import (
20+
"strconv"
21+
2022
"github.com/openebs/lib-csi/pkg/common/errors"
2123
apis "github.com/openebs/lvm-localpv/pkg/apis/openebs.io/lvm/v1alpha1"
24+
"k8s.io/apimachinery/pkg/api/resource"
2225
)
2326

2427
// Builder is the builder object for LVMVolume
@@ -139,6 +142,85 @@ func (b *Builder) WithThinProvision(thinProvision string) *Builder {
139142
return b
140143
}
141144

145+
// WithRaidType sets the RAID type for all logical volumes in the volume group
146+
func (b *Builder) WithRaidType(raidType string) *Builder {
147+
b.volume.Object.Spec.RaidType = raidType
148+
return b
149+
}
150+
151+
// WithIntegrity sets where integrity is enable or not
152+
func (b *Builder) WithIntegrity(integrity string) *Builder {
153+
b.volume.Object.Spec.Integrity = integrity
154+
return b
155+
}
156+
157+
// WithMirrors sets the RAID mirror count
158+
func (b *Builder) WithMirrors(mirrors string) *Builder {
159+
mirrorCount, err := strconv.ParseUint(mirrors, 10, 32)
160+
if err != nil {
161+
b.errs = append(
162+
b.errs,
163+
errors.New(
164+
"invalid mirror count: must be a positive 32-bit integer",
165+
),
166+
err,
167+
)
168+
}
169+
170+
b.volume.Object.Spec.Mirrors = uint(mirrorCount)
171+
return b
172+
}
173+
174+
// WithNoSync sets the `nosync` RAID option
175+
func (b *Builder) WithNoSync(nosync string) *Builder {
176+
b.volume.Object.Spec.NoSync = nosync
177+
return b
178+
}
179+
180+
func (b *Builder) WithStripeCount(stripes string) *Builder {
181+
stripeCount, err := strconv.ParseUint(stripes, 10, 32)
182+
if err != nil {
183+
b.errs = append(
184+
b.errs,
185+
errors.New(
186+
"invalid stripe count: must be a positive 32-bit integer",
187+
),
188+
err,
189+
)
190+
}
191+
192+
b.volume.Object.Spec.StripeCount = uint(stripeCount)
193+
return b
194+
}
195+
196+
// WithStripeSize sets the size of each stripe for a RAID volume
197+
func (b *Builder) WithStripeSize(size string) *Builder {
198+
stripeSize, err := resource.ParseQuantity(size)
199+
if err != nil {
200+
b.errs = append(
201+
b.errs,
202+
errors.New(
203+
"invalid stripe size",
204+
),
205+
err,
206+
)
207+
}
208+
209+
value := stripeSize.Value()
210+
if value < 0 {
211+
b.errs = append(b.errs, errors.New("invalid stripe size: value must be positive"))
212+
}
213+
214+
b.volume.Object.Spec.StripeSize = uint(value)
215+
return b
216+
}
217+
218+
// WithLvCreateOptions sets any additional LVM options used when creating a volume
219+
func (b *Builder) WithLvCreateOptions(options string) *Builder {
220+
b.volume.Object.Spec.LvCreateOptions = options
221+
return b
222+
}
223+
142224
// WithVolGroup sets volume group name for creating volume
143225
func (b *Builder) WithVolGroup(vg string) *Builder {
144226
if vg == "" {

0 commit comments

Comments
 (0)