xref: /freebsd/usr.sbin/ctladm/tests/port.sh (revision 582f787e2a5c3114819dfaa4611cb4762716f0a1)
1# SPDX-License-Identifier: BSD-2-Clause
2#
3# Copyright (c) 2024 Axcient
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS DOCUMENTATION IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26# Things that aren't tested due to lack of kernel support:
27# * Creating camsim ports
28# * Creating tpc ports
29# * Creating camtgt ports
30# * Creating umass ports
31
32# TODO
33# * Creating nvmf ports
34# * Creating ha ports
35# * Creating fc ports
36
37# The PGTAG can be any 16-bit number.  The only constraint is that each
38# PGTAG,TARGET pair must be globally unique.
39PGTAG=30257
40
41load_cfiscsi() {
42	if ! kldstat -q -m cfiscsi; then
43		kldload cfiscsi || atf_skip "could not load cfscsi kernel mod"
44	fi
45}
46
47skip_if_ctld() {
48	if service ctld onestatus > /dev/null; then
49		# If ctld is running on this server, let's not interfere.
50		atf_skip "Cannot run this test while ctld is running"
51	fi
52}
53
54cleanup() {
55	driver=$1
56
57	if [ -e port-create.txt ]; then
58		case "$driver" in
59		"ioctl")
60			PORTNUM=`awk '/port:/ {print $2}' port-create.txt`
61			ctladm port -r -d $driver -p $PORTNUM
62			;;
63		"iscsi")
64			TARGET=`awk '/target:/ {print $2}' port-create.txt`
65			ctladm port -r -d $driver -O cfiscsi_portal_group_tag=$PGTAG -O cfiscsi_target=$TARGET
66			;;
67		esac
68	fi
69}
70
71atf_test_case create_ioctl cleanup
72create_ioctl_head()
73{
74	atf_set "descr" "ctladm can create a new ioctl port"
75	atf_set "require.user" "root"
76	atf_set "require.progs" ctladm
77}
78create_ioctl_body()
79{
80	skip_if_ctld
81
82	atf_check -o save:port-create.txt ctladm port -c -d "ioctl"
83	atf_check egrep -q "Port created successfully" port-create.txt
84	atf_check egrep -q "frontend: *ioctl" port-create.txt
85	atf_check egrep -q "port: *[0-9]+" port-create.txt
86	portnum=`awk '/port:/ {print $2}' port-create.txt`
87	atf_check -o save:portlist.txt ctladm portlist -qf ioctl
88	atf_check egrep -q "$portnum *YES *ioctl *ioctl" portlist.txt
89}
90create_ioctl_cleanup()
91{
92	cleanup ioctl
93}
94
95atf_test_case remove_ioctl_without_required_args cleanup
96remove_ioctl_without_required_args_head()
97{
98	atf_set "descr" "ctladm will gracefully fail to remove an ioctl target if required arguments are missing"
99	atf_set "require.user" "root"
100	atf_set "require.progs" ctladm
101}
102remove_ioctl_without_required_args_body()
103{
104	skip_if_ctld
105
106	atf_check -o save:port-create.txt ctladm port -c -d "ioctl"
107	atf_check egrep -q "Port created successfully" port-create.txt
108	atf_check -s exit:1 -e match:"Missing required argument: port_id" ctladm port -r -d "ioctl"
109}
110remove_ioctl_without_required_args_cleanup()
111{
112	cleanup ioctl
113}
114
115atf_test_case create_iscsi cleanup
116create_iscsi_head()
117{
118	atf_set "descr" "ctladm can create a new iscsi port"
119	atf_set "require.user" "root"
120	atf_set "require.progs" ctladm
121}
122create_iscsi_body()
123{
124	skip_if_ctld
125	load_cfiscsi
126
127	TARGET=iqn.2018-10.myhost.create_iscsi
128	atf_check -o save:port-create.txt ctladm port -c -d "iscsi" -O cfiscsi_portal_group_tag=$PGTAG -O cfiscsi_target="$TARGET"
129	echo "target: $TARGET" >> port-create.txt
130	atf_check egrep -q "Port created successfully" port-create.txt
131	atf_check egrep -q "frontend: *iscsi" port-create.txt
132	atf_check egrep -q "port: *[0-9]+" port-create.txt
133	atf_check -o save:portlist.txt ctladm portlist -qf iscsi
134	# Unlike the ioctl driver, the iscsi driver creates ports in a disabled
135	# state, so the port's lunmap may be set before enabling it.
136	atf_check egrep -q "$portnum *NO *iscsi *iscsi.*$TARGET" portlist.txt
137}
138create_iscsi_cleanup()
139{
140	cleanup iscsi
141}
142
143atf_test_case create_iscsi_alias cleanup
144create_iscsi_alias_head()
145{
146	atf_set "descr" "ctladm can create a new iscsi port with a target alias"
147	atf_set "require.user" "root"
148	atf_set "require.progs" ctladm
149}
150create_iscsi_alias_body()
151{
152	skip_if_ctld
153	load_cfiscsi
154
155	TARGET=iqn.2018-10.myhost.create_iscsi_alias
156	ALIAS="foobar"
157	atf_check -o save:port-create.txt ctladm port -c -d "iscsi" -O cfiscsi_portal_group_tag=$PGTAG -O cfiscsi_target="$TARGET" -O cfiscsi_target_alias="$ALIAS"
158	echo "target: $TARGET" >> port-create.txt
159	atf_check egrep -q "Port created successfully" port-create.txt
160	atf_check egrep -q "frontend: *iscsi" port-create.txt
161	atf_check egrep -q "port: *[0-9]+" port-create.txt
162	atf_check -o save:portlist.txt ctladm portlist -qvf iscsi
163	atf_check egrep -q "cfiscsi_target_alias=$ALIAS" portlist.txt
164}
165create_iscsi_alias_cleanup()
166{
167	cleanup iscsi
168}
169
170atf_test_case create_iscsi_without_required_args
171create_iscsi_without_required_args_head()
172{
173	atf_set "descr" "ctladm will gracefully fail to create an iSCSI target if required arguments are missing"
174	atf_set "require.user" "root"
175	atf_set "require.progs" ctladm
176}
177create_iscsi_without_required_args_body()
178{
179	skip_if_ctld
180	load_cfiscsi
181
182	TARGET=iqn.2018-10.myhost.create_iscsi
183	atf_check -s exit:1 -e match:"Missing required argument: cfiscsi_target" ctladm port -c -d "iscsi" -O cfiscsi_portal_group_tag=$PGTAG
184	atf_check -s exit:1 -e match:"Missing required argument: cfiscsi_portal_group_tag" ctladm port -c -d "iscsi" -O cfiscsi_target=$TARGET
185}
186
187atf_test_case create_ioctl_options cleanup
188create_ioctl_options_head()
189{
190	atf_set "descr" "ctladm can set options when creating a new ioctl port"
191	atf_set "require.user" "root"
192	atf_set "require.progs" ctladm
193}
194create_ioctl_options_body()
195{
196	skip_if_ctld
197
198	atf_check -o save:port-create.txt ctladm port -c -d "ioctl" -O pp=101 -O vp=102
199	atf_check egrep -q "Port created successfully" port-create.txt
200	atf_check egrep -q "frontend: *ioctl" port-create.txt
201	atf_check egrep -q "port: *[0-9]+" port-create.txt
202	portnum=`awk '/port:/ {print $2}' port-create.txt`
203	atf_check -o save:portlist.txt ctladm portlist -qf ioctl
204	if ! egrep -q '101[[:space:]]+102' portlist.txt; then
205		ctladm portlist
206		atf_fail "Did not create the port with the specified options"
207	fi
208}
209create_ioctl_options_cleanup()
210{
211	cleanup ioctl
212}
213
214
215atf_test_case disable_ioctl cleanup
216disable_ioctl_head()
217{
218	atf_set "descr" "ctladm can disable an ioctl port"
219	atf_set "require.user" "root"
220	atf_set "require.progs" ctladm
221}
222disable_ioctl_body()
223{
224	skip_if_ctld
225
226	atf_check -o save:port-create.txt ctladm port -c -d "ioctl"
227	portnum=`awk '/port:/ {print $2}' port-create.txt`
228	atf_check -o save:portlist.txt ctladm portlist -qf ioctl
229	atf_check -o ignore ctladm port -o off -p $portnum
230	atf_check -o match:"^$portnum *NO" ctladm portlist -qf ioctl
231}
232disable_ioctl_cleanup()
233{
234	cleanup ioctl
235}
236
237atf_test_case enable_ioctl cleanup
238enable_ioctl_head()
239{
240	atf_set "descr" "ctladm can enable an ioctl port"
241	atf_set "require.user" "root"
242	atf_set "require.progs" ctladm
243}
244enable_ioctl_body()
245{
246	skip_if_ctld
247
248	atf_check -o save:port-create.txt ctladm port -c -d "ioctl"
249	portnum=`awk '/port:/ {print $2}' port-create.txt`
250	atf_check -o save:portlist.txt ctladm portlist -qf ioctl
251	atf_check -o ignore ctladm port -o off -p $portnum
252	atf_check -o ignore ctladm port -o on -p $portnum
253	atf_check -o match:"^$portnum *YES" ctladm portlist -qf ioctl
254}
255enable_ioctl_cleanup()
256{
257	cleanup ioctl
258}
259
260atf_test_case remove_ioctl
261remove_ioctl_head()
262{
263	atf_set "descr" "ctladm can remove an ioctl port"
264	atf_set "require.user" "root"
265	atf_set "require.progs" ctladm
266}
267remove_ioctl_body()
268{
269	skip_if_ctld
270
271	# Specify exact pp and vp to make the post-removal portlist check
272	# unambiguous
273	atf_check -o save:port-create.txt ctladm port -c -d "ioctl" -O pp=10001 -O vp=10002
274	portnum=`awk '/port:/ {print $2}' port-create.txt`
275	atf_check -o save:portlist.txt ctladm portlist -qf ioctl
276	atf_check -o inline:"Port destroyed successfully\n" ctladm port -r -d ioctl -p $portnum
277	# Check that the port was removed.  A new port may have been added with
278	# the same ID, so match against the pp and vp numbers, too.
279	if ctladm portlist -qf ioctl | egrep -q "^${portnum} .*10001 *10002"; then
280		ctladm portlist -qf ioctl
281		atf_fail "port was not removed"
282	fi
283}
284
285atf_test_case remove_iscsi
286remove_iscsi_head()
287{
288	atf_set "descr" "ctladm can remove an iscsi port"
289	atf_set "require.user" "root"
290	atf_set "require.progs" ctladm
291}
292remove_iscsi_body()
293{
294	skip_if_ctld
295	load_cfiscsi
296
297	TARGET=iqn.2018-10.myhost.remove_iscsi
298	atf_check -o save:port-create.txt ctladm port -c -d "iscsi" -O cfiscsi_portal_group_tag=$PGTAG -O cfiscsi_target="$TARGET"
299	portnum=`awk '/port:/ {print $2}' port-create.txt`
300	atf_check -o save:portlist.txt ctladm portlist -qf iscsi
301	atf_check -o inline:"Port destroyed successfully\n" ctladm port -r -d iscsi -O cfiscsi_portal_group_tag=$PGTAG -O cfiscsi_target="$TARGET"
302	# Check that the port was removed.  A new port may have been added with
303	# the same ID, so match against the target and tag, too.
304	PGTAGHEX=0x7631	# PGTAG in hex
305	if ctladm portlist -qf iscsi | egrep -q "^${portnum} .*$PGTAG +[0-9]+ +$TARGET,t,$PGTAGHEX"; then
306		ctladm portlist -qf iscsi
307		atf_fail "port was not removed"
308	fi
309}
310
311atf_test_case remove_iscsi_without_required_args cleanup
312remove_iscsi_without_required_args_head()
313{
314	atf_set "descr" "ctladm will gracefully fail to remove an iSCSI target if required arguments are missing"
315	atf_set "require.user" "root"
316	atf_set "require.progs" ctladm
317}
318remove_iscsi_without_required_args_body()
319{
320	skip_if_ctld
321	load_cfiscsi
322
323	TARGET=iqn.2018-10.myhost.remove_iscsi_without_required_args
324	atf_check -o save:port-create.txt ctladm port -c -d "iscsi" -O cfiscsi_portal_group_tag=$PGTAG -O cfiscsi_target="$TARGET"
325	echo "target: $TARGET" >> port-create.txt
326	atf_check -s exit:1 -e match:"Missing required argument: cfiscsi_portal_group_tag" ctladm port -r -d iscsi -O cfiscsi_target="$TARGET"
327	atf_check -s exit:1 -e match:"Missing required argument: cfiscsi_target" ctladm port -r -d iscsi -O cfiscsi_portal_group_tag=$PGTAG
328}
329remove_iscsi_without_required_args_cleanup()
330{
331	cleanup iscsi
332}
333
334atf_init_test_cases()
335{
336	atf_add_test_case create_ioctl
337	atf_add_test_case create_iscsi
338	atf_add_test_case create_iscsi_without_required_args
339	atf_add_test_case create_iscsi_alias
340	atf_add_test_case create_ioctl_options
341	atf_add_test_case disable_ioctl
342	atf_add_test_case enable_ioctl
343	atf_add_test_case remove_ioctl
344	atf_add_test_case remove_ioctl_without_required_args
345	atf_add_test_case remove_iscsi
346	atf_add_test_case remove_iscsi_without_required_args
347}
348