-
Notifications
You must be signed in to change notification settings - Fork 2
/
daemon_test.go
334 lines (287 loc) · 12.4 KB
/
daemon_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/*
Copyright 2016 The Rook Authors. All rights reserved.
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 osd
import (
"io/ioutil"
"os"
"strings"
"testing"
"github.com/pkg/errors"
"github.com/rook/rook/pkg/clusterd"
cephconfig "github.com/rook/rook/pkg/daemon/ceph/config"
"github.com/rook/rook/pkg/operator/ceph/cluster/osd/config"
exectest "github.com/rook/rook/pkg/util/exec/test"
"github.com/rook/rook/pkg/util/sys"
"github.com/stretchr/testify/assert"
)
const udevFSOutput = `
DEVNAME=/dev/sdk
DEVPATH=/devices/platform/host6/session2/target6:0:0/6:0:0:0/block/sdk
DEVTYPE=disk
ID_BUS=scsi
ID_FS_TYPE=ext2
ID_FS_USAGE=filesystem
ID_FS_UUID=f2d38cba-37da-411d-b7ba-9a6696c58174
ID_FS_UUID_ENC=f2d38cba-37da-411d-b7ba-9a6696c58174
ID_FS_VERSION=1.0
ID_MODEL=disk01
ID_MODEL_ENC=disk01\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
ID_PATH=ip-127.0.0.1:3260-iscsi-iqn.2016-06.world.srv:storage.target01-lun-0
ID_PATH_TAG=ip-127_0_0_1_3260-iscsi-iqn_2016-06_world_srv_storage_target01-lun-0
ID_REVISION=4.0
ID_SCSI=1
ID_SCSI_SERIAL=d27e5d89-8829-468b-90ce-4ef8c02f07fe
ID_SERIAL=36001405d27e5d898829468b90ce4ef8c
ID_SERIAL_SHORT=6001405d27e5d898829468b90ce4ef8c
ID_TARGET_PORT=0
ID_TYPE=disk
ID_VENDOR=LIO-ORG
ID_VENDOR_ENC=LIO-ORG\x20
ID_WWN=0x6001405d27e5d898
ID_WWN_VENDOR_EXTENSION=0x829468b90ce4ef8c
ID_WWN_WITH_EXTENSION=0x6001405d27e5d898829468b90ce4ef8c
MAJOR=8
MINOR=160
SUBSYSTEM=block
TAGS=:systemd:
USEC_INITIALIZED=15981915740802
`
func TestRunDaemon(t *testing.T) {
configDir, _ := ioutil.TempDir("", "")
defer os.RemoveAll(configDir)
os.MkdirAll(configDir, 0755)
defBkp := cephconfig.DefaultConfigDir
cephconfig.DefaultConfigDir = configDir
defer func() { cephconfig.DefaultConfigDir = defBkp }()
agent, _, context := createTestAgent(t, "none", configDir, "node5375", &config.StoreConfig{StoreType: config.Bluestore})
agent.devices[0].IsFilter = true
agent.pvcBacked = false
logger.Infof("Agent %+v", agent)
crushLocation := "root=default host=foo"
err := Provision(context, agent, crushLocation)
assert.Nil(t, err)
}
func TestGetDataDirs(t *testing.T) {
configDir, _ := ioutil.TempDir("", "")
defer os.RemoveAll(configDir)
context := &clusterd.Context{ConfigDir: configDir}
defer os.RemoveAll(context.ConfigDir)
os.MkdirAll(context.ConfigDir, 0755)
kv := mockKVStore()
nodeName := "node6046"
// user has specified devices to use, no dirs should be returned
dirMap, removedDirMap, err := getDataDirs(context, kv, "", true, nodeName)
assert.Nil(t, err)
assert.Equal(t, 0, len(dirMap))
assert.Equal(t, 0, len(removedDirMap))
// user has no devices specified, should NO LONGER return default dir
dirMap, removedDirMap, err = getDataDirs(context, kv, "", false, nodeName)
assert.Nil(t, err)
assert.Equal(t, 0, len(dirMap))
assert.Equal(t, 0, len(removedDirMap))
// user has no devices specified but does specify dirs, those should be returned
dirMap, removedDirMap, err = getDataDirs(context, kv, "/rook/dir1", false, nodeName)
assert.Nil(t, err)
assert.Equal(t, 1, len(dirMap))
assert.Equal(t, unassignedOSDID, dirMap["/rook/dir1"])
assert.Equal(t, 0, len(removedDirMap))
// user has devices specified and also specifies dirs, those should be returned
dirMap, removedDirMap, err = getDataDirs(context, kv, "/rook/dir1", true, nodeName)
assert.Nil(t, err)
assert.Equal(t, 1, len(dirMap))
assert.Equal(t, unassignedOSDID, dirMap["/rook/dir1"])
assert.Equal(t, 0, len(removedDirMap))
// simulate an OSD ID being assigned to the dir
dirMap["/rook/dir1"] = 1
// save the directory config
err = config.SaveOSDDirMap(kv, nodeName, dirMap)
assert.Nil(t, err)
// user has specified devices and also a new directory to use. it should be added to the dir map
dirMap, removedDirMap, err = getDataDirs(context, kv, "/rook/dir1,/tmp/mydir", true, nodeName)
assert.Nil(t, err)
assert.Equal(t, 2, len(dirMap))
assert.Equal(t, 1, dirMap["/rook/dir1"])
assert.Equal(t, unassignedOSDID, dirMap["/tmp/mydir"])
assert.Equal(t, 0, len(removedDirMap))
// simulate that the user's dir got an OSD by assigning it an ID
dirMap["/tmp/mydir"] = 23
err = config.SaveOSDDirMap(kv, nodeName, dirMap)
assert.Nil(t, err)
// user is still specifying the 2 directories, we should get back their IDs
dirMap, removedDirMap, err = getDataDirs(context, kv, "/rook/dir1,/tmp/mydir", true, nodeName)
assert.Nil(t, err)
assert.Equal(t, 2, len(dirMap))
assert.Equal(t, 1, dirMap["/rook/dir1"])
assert.Equal(t, 23, dirMap["/tmp/mydir"])
assert.Equal(t, 0, len(removedDirMap))
// user is now only specifying 1 of the dirs, the other 1 should be returned as removed
dirMap, removedDirMap, err = getDataDirs(context, kv, "/rook/dir1", true, nodeName)
assert.Nil(t, err)
assert.Equal(t, 1, len(dirMap))
assert.Equal(t, 1, dirMap["/rook/dir1"])
assert.Equal(t, 1, len(removedDirMap))
assert.Equal(t, 23, removedDirMap["/tmp/mydir"])
// clear the dir map and simulate the scenario where an OSD has been created in the default dir
kv.ClearStore(config.GetConfigStoreName(nodeName))
osdID := 9802
dirMap = map[string]int{context.ConfigDir: osdID}
err = config.SaveOSDDirMap(kv, nodeName, dirMap)
assert.Nil(t, err)
// when an OSD has been created in the default dir, no dirs are specified, and no devices are specified,
// the default dir should still be in use (it should not come back as removed!)
dirMap, removedDirMap, err = getDataDirs(context, kv, "", false, nodeName)
assert.Nil(t, err)
assert.Equal(t, 1, len(dirMap))
assert.Equal(t, osdID, dirMap[context.ConfigDir])
assert.Equal(t, 0, len(removedDirMap))
// if devices are specified (but no dirs), the existing osd in the default dir will not be preserved
dirMap, removedDirMap, err = getDataDirs(context, kv, "", true, nodeName)
assert.Nil(t, err)
assert.Equal(t, 0, len(dirMap))
assert.Equal(t, 1, len(removedDirMap))
assert.Equal(t, osdID, removedDirMap[context.ConfigDir])
}
func TestAvailableDevices(t *testing.T) {
executor := &exectest.MockExecutor{}
// set up a mock function to return "rook owned" partitions on the device and it does not have a filesystem
executor.MockExecuteCommandWithOutput = func(debug bool, name string, command string, args ...string) (string, error) {
logger.Infof("OUTPUT for %s. %s %+v", name, command, args)
if command == "lsblk" {
if strings.Index(name, "sdb") != -1 {
// /dev/sdb has a partition
return `NAME="sdb" SIZE="65" TYPE="disk" PKNAME=""
NAME="sdb1" SIZE="30" TYPE="part" PKNAME="sdb"`, nil
}
return "", nil
} else if command == "blkid" {
if strings.Index(name, "sdb1") != -1 {
// partition sdb1 has a label MY-PART
return "MY-PART", nil
}
} else if command == "udevadm" {
if strings.Index(name, "sdc") != -1 {
// /dev/sdc has a file system
return udevFSOutput, nil
}
return "", nil
}
return "", errors.Errorf("unknown command %s %s", command, args)
}
context := &clusterd.Context{Executor: executor}
context.Devices = []*sys.LocalDisk{
{Name: "sda", DevLinks: "/dev/disk/by-id/scsi-0123 /dev/disk/by-path/pci-0:1:2:3-scsi-1"},
{Name: "sdb", DevLinks: "/dev/disk/by-id/scsi-4567 /dev/disk/by-path/pci-4:5:6:7-scsi-1"},
{Name: "sdc", DevLinks: "/dev/disk/by-id/scsi-89ab /dev/disk/by-path/pci-8:9:a:b-scsi-1"},
{Name: "sdd", DevLinks: "/dev/disk/by-id/scsi-cdef /dev/disk/by-path/pci-c:d:e:f-scsi-1"},
{Name: "sde", DevLinks: "/dev/disk/by-id/sde-0x0000 /dev/disk/by-path/pci-0000:00:18.0-ata-1"},
{Name: "nvme01", DevLinks: "/dev/disk/by-id/nvme-0246 /dev/disk/by-path/pci-0:2:4:6-nvme-1"},
{Name: "rda"},
{Name: "rdb"},
}
// select all devices, including nvme01 for metadata
pvcBackedOSD := false
mapping, err := getAvailableDevices(context, []DesiredDevice{{Name: "all"}}, "nvme01", pvcBackedOSD)
assert.Nil(t, err)
assert.Equal(t, 6, len(mapping.Entries))
assert.Equal(t, -1, mapping.Entries["sda"].Data)
assert.Equal(t, -1, mapping.Entries["sdd"].Data)
assert.Equal(t, -1, mapping.Entries["rda"].Data)
assert.Equal(t, -1, mapping.Entries["rdb"].Data)
assert.Equal(t, -1, mapping.Entries["nvme01"].Data)
assert.NotNil(t, mapping.Entries["nvme01"].Metadata)
assert.Equal(t, 0, len(mapping.Entries["nvme01"].Metadata))
// select no devices both using and not using a filter
mapping, err = getAvailableDevices(context, nil, "", pvcBackedOSD)
assert.Nil(t, err)
assert.Equal(t, 0, len(mapping.Entries))
mapping, err = getAvailableDevices(context, nil, "", pvcBackedOSD)
assert.Nil(t, err)
assert.Equal(t, 0, len(mapping.Entries))
// select the sd* devices
mapping, err = getAvailableDevices(context, []DesiredDevice{{Name: "^sd.$", IsFilter: true}}, "", pvcBackedOSD)
assert.Nil(t, err)
assert.Equal(t, 3, len(mapping.Entries))
assert.Equal(t, -1, mapping.Entries["sda"].Data)
assert.Equal(t, -1, mapping.Entries["sdd"].Data)
// select an exact device
mapping, err = getAvailableDevices(context, []DesiredDevice{{Name: "sdd"}}, "", pvcBackedOSD)
assert.Nil(t, err)
assert.Equal(t, 1, len(mapping.Entries))
assert.Equal(t, -1, mapping.Entries["sdd"].Data)
// select all devices except those that have a prefix of "s"
mapping, err = getAvailableDevices(context, []DesiredDevice{{Name: "^[^s]", IsFilter: true}}, "", pvcBackedOSD)
assert.Nil(t, err)
assert.Equal(t, 3, len(mapping.Entries))
assert.Equal(t, -1, mapping.Entries["rda"].Data)
assert.Equal(t, -1, mapping.Entries["rdb"].Data)
assert.Equal(t, -1, mapping.Entries["nvme01"].Data)
// select the sd* devices by path names
mapping, err = getAvailableDevices(context, []DesiredDevice{{Name: "^/dev/sd.$", IsDevicePathFilter: true}}, "", pvcBackedOSD)
assert.Nil(t, err)
assert.Equal(t, 3, len(mapping.Entries))
assert.Equal(t, -1, mapping.Entries["sda"].Data)
assert.Equal(t, -1, mapping.Entries["sdd"].Data)
// select the SCSI devices
mapping, err = getAvailableDevices(context, []DesiredDevice{{Name: "^/dev/disk/by-path/.*-scsi-.*", IsDevicePathFilter: true}}, "", pvcBackedOSD)
assert.Nil(t, err)
assert.Equal(t, 2, len(mapping.Entries))
assert.Equal(t, -1, mapping.Entries["sda"].Data)
// select a device by explicit link
mapping, err = getAvailableDevices(context, []DesiredDevice{{Name: "/dev/disk/by-id/sde-0x0000"}}, "", pvcBackedOSD)
assert.Nil(t, err)
assert.Equal(t, 1, len(mapping.Entries))
assert.Equal(t, -1, mapping.Entries["sde"].Data)
}
func TestGetRemovedDevices(t *testing.T) {
testGetRemovedDevicesHelper(t, &config.StoreConfig{StoreType: config.Bluestore})
testGetRemovedDevicesHelper(t, &config.StoreConfig{StoreType: config.Filestore})
}
func testGetRemovedDevicesHelper(t *testing.T, storeConfig *config.StoreConfig) {
configDir, _ := ioutil.TempDir("", "")
defer os.RemoveAll(configDir)
os.MkdirAll(configDir, 0755)
nodeName := "node3391"
agent, _, _ := createTestAgent(t, "none", configDir, nodeName, storeConfig)
agent.devices[0].IsFilter = true
// mock the pre-existence of osd 1 on device sdx
_, _, _ = mockPartitionSchemeEntry(t, 1, "sdx", &agent.storeConfig, agent.kv, nodeName)
// get the removed devices for this configuration (note we said to use devices "none" above),
// it should be osd 1 on device sdx
scheme, mapping, err := getRemovedDevices(agent)
assert.Nil(t, err)
assert.Equal(t, 1, len(mapping.Entries))
assert.Equal(t, 1, len(scheme.Entries))
// assert the scheme has an entry for osd 1 and its data partition is on sdx
schemeEntry := scheme.Entries[0]
assert.Equal(t, 1, schemeEntry.ID)
assert.Equal(t, "sdx", schemeEntry.Partitions[schemeEntry.GetDataPartitionType()].Device)
// assert the removed device mapping has an entry for device sdx and it points to osd 1
mappingEntry, ok := mapping.Entries["sdx"]
assert.True(t, ok)
assert.NotNil(t, mappingEntry)
assert.Equal(t, 1, mappingEntry.Data)
}
func TestGetVolumeGroupName(t *testing.T) {
validLVPath := "/dev/vgName1/lvName2"
invalidLVPath1 := "/dev//vgName2"
invalidLVPath2 := "/dev/"
vgName, err := getVolumeGroupName(validLVPath)
assert.Nil(t, err)
assert.Equal(t, vgName, "vgName1")
vgName, err = getVolumeGroupName(invalidLVPath1)
assert.NotNil(t, err)
assert.Equal(t, vgName, "")
vgName, err = getVolumeGroupName(invalidLVPath2)
assert.NotNil(t, err)
assert.Equal(t, vgName, "")
}