分类: 服务器与存储
2011-12-20 12:44:25
级别: 中级
齐 慧 , 软件工程师, IBM China Systems & Technology Lab (CSTL) 上海
2007 年 10 月 29 日
本文向您介绍了如何利用 UNIX 的脚本功能生成能够在 DS4000 上使用的控制脚本。它是文章作者在实际工作中的总结,具有比较高的实用性,同时对于类似的问题的解决也是一个很有启发的例子。文中使用了著名的编辑器 SED,对于这方面感兴趣的读者也是很有帮助的。
为什么使用 UNIX 脚本来管理 DS4000
作为一个测试工程师,在我的日常工作中我经常要花费大量的时间去完成一些很简单但是很耗时的工作。例如,一次我想在 DS4000 上创建 200 个磁盘。但是由于 DS4000 没有能够批量创建磁盘的功能,我花费了 4 个小时一个一个地去创建。这次的经历使我有一种想法去创建一个能够可以批量地创建磁盘的工具。经过我一段时间的研究,我发现 IBM Storage Manager 支持 CLI(Command Line Interface)功能,这就意味着我可以利用 UNIX 系统的脚本功能来创建一个可以被 IBM Storage Manager 使用的脚本。通过在 IBM Storage Manager 运行这个被创建的脚本,可以在无需人机交互的情况下批量的创建磁盘。但是作者并不保证本方法在任何情况下总是可以成功,请读者在验证本文的例子时注意做好相应的备份,最好在实验环境上进行操作。
例子脚本介绍
那么如何创建 IBM Storage Manager 可使用的脚本呢?IBM Storage Manager 有它自己的脚本格式。只有脚本的变量值改变而格式并不改变。所以,UNIX 脚本需要能够让用户能够定制的输入自己的所对应的值,如需要创建磁盘的数量,HBA 卡的 WWPNs 值,来生成 IBM Storage Manager 能够使用的脚本文件。可以设计一个配置文件来让用户输入自己对应的变量值。下面就是个配置文件的例子:
LunNumber:30 #30 个 LUNs
ArrayNumber:1 # 这些 LUNs 创建在 array 1 上
LunName:sunx325b # 这些 LUNs 的名字将为 sunx325b_0, sunx325b_1 ...
Capacity:0.5GB # 每个 LUNs 的容量是 0.5GB
HostGroupName:sunx325b_group # 这个主机组的名字为 sunx325b_group
HostName:sunx325b # 这个主机名为 sunx325b
Port0:210000e08b0e934d # 第一个 HBA 卡的 wwpn 值
Port1:210000e08b0e6e50 # 第二个 HBA 卡的 wwpn 值
HostType:8 # 主机类型
完成了对配置文件的定义以后,UNIX 脚本可以把配置文件中用户定义的值解析出来,并且组织成为 IBM Storage Manager 可以使用的脚本。一个比较好的解析配置文件的工具是 SED 编辑器,这是一个流式的编辑器。SED 编辑器将需要处理的文本作为输入,经过一系列操作以后,输出经过修改的文本。SED 编辑器的典型应用就是通过模式的匹配来提取文件中的一部分内容或者是把文件中的多个相同的字符串进行替换。UNIX 脚本可以通过使用 SED 编辑器从配置文件中得到需要的数值,并把这些值添加到能够被 IBM Storage Manager 使用的脚本中去。
例如,下面展示了如何使用 UNIX 脚本从配置文件中获取磁盘数量这个值。这个脚本从配置文件获取 LunNumber 这个值,然后把这个值赋给脚本中的对应变量 LunNumber。
sed -n '/LunNumber:/'p $ConfigFile >tmp
lunNumber=`sed 's/LunNumber://' tmp`
例子脚本的详细说明
下面的例子是展示如何使用 SED 编辑器生成一个 IBM Storage Manager 可以使用的脚本。这个例子中,脚本从配置文件中获得了 ArrayNumber,LunName 和 Capacity 的值,用于生成 IBM Storage Manager 使用的生成磁盘的命令,然后把这个命令添加到 IBM Storage Manager 的脚本(crtlun.cmd)文件。
x=0
while [ $x -lt $lunNumber ]
do
y=`expr $x % 2`
if [ $y -eq 0 ]
then
echo "create logicalDrive array=$arrayNumber userLabel=\"${lunName}_${x}\"
capacity=$capacity owner=a;" >> crtlun.cmd
else
echo "create logicalDrive array=$arrayNumber userLabel=\"${lunName}_${x}\"
capacity=$capacity owner=b;" >> crtlun.cmd
fi
x=`expr $x + 1`
done
这个 UNIX 工具的内容是不是很简单?但是它却帮助了我把原来需要几个小时的工作减少为只需要几分钟就可以完成。下面让我对我的 UNIX 脚本文件的内容做个比较详细的介绍。这个名字为 ds4kscript.sh 的脚本文件可以运行在 UNIX(AIX,Solaris,Linux 等)上,用于产生一个可以在 IBM Storage Manager 上运行的脚本。它可以用于在 DS4000 系列上创建和删除 Lun、host group、host、host port,映射 Lun 等功能。
这个脚本的输入是配置文件:config。它保存这用户自定义的配置信息。这个脚本的输出是一系列的脚本(这个功能在后面会加以介绍):crtlun.cmd, crthost.cmd, maplun.cmd, delmap.cmd, delhost.cmd, dellun.cmd, setup.cmd, destroy.cmd 支持的操作系统:AIX,Solaris 和 Linux
脚本使用说明
编辑 config 文件,设置参数为用户所需要的值。下面是一个例子,显示了 config 文件需要包含那些项以及一些说明:
LunNumber:30 #30 个 LUNs
ArrayNumber:1 # 这些 LUNs 创建在 array 1 上
LunName:sunx325b # 这些 LUNs 的名字将为 sunx325b_0, sunx325b_1 ...
Capacity:0.5GB # 每个 LUNs 的容量是 0.5GB
HostGroupName:sunx325b_group # 这个主机组的名字为 sunx325b_group
HostName:sunx325b # 这个主机名为 sunx325b
Port0:210000e08b0e934d # 第一个 HBA 卡的 wwpn 值
Port1:210000e08b0e6e50 # 第二个 HBA 卡的 wwpn 值
HostType:8 # 主机类型
复制 ds4kscript.sh 到和 config 相同的目录下,执行:
chmod +x ds4kscript.sh (使用户对 ds4kscript.sh 具有执行权限)
./ds4kscript.sh ( 执行 ds4kscript.sh)
在 ds4kscript.sh 运行的目录下,一系列文件将会被创建出来:crtlun.cmd, crthost.cmd, maplun.cmd, delmap.cmd, delhost.cmd, dellun.cmd, setup.cmd, destroy.cmd。下面逐一对这些文件的功能进行描述:
* 创建 Lun、host group、host、host port,映射 Lun。它包括了 crtlun.cmd, crthost.cmd, maplun.cmd 的所有功能,算是一个功能集合的脚本。
* 创建 Luns;
* 创建 host group、host、host port;
* 映射端口到 host 上;
* 删除 Lun、host group、host、host port,映射 Lun。它包括了 delmap.cmd, delhost.cmd, dellun.cmd 的所有功能,算是一个功能集合的脚本;
* 删除 Lun 映射
* 删除 host group、host、host port
* 删除 Lun
复制 setup.cmd 的内容到 IBM Storage Manager 脚本编辑器中,然后运行它。或者用户也可以单独的复制 crtlun.cmd, crthost.cmd, maplun.cmd 中的内容,来实现单独的一些功能。这时 Lun 已经在 DS4000 上建立好了,同时也映射到了主机上。
当然,同时可以执行 destroy.cmd 内的内容来进行删除操作,或者单独地执行 delmap.cmd, delhost.cmd, dellun.cmd 内的内容来清除刚才执行的创建操作。
下面是 ds4kscript.sh 的详细内容,请注意其中的注解内容,会帮助您的理解:
下面是 ds4kscript.sh 的详细内容,请注意其中的注解内容,会帮助您的理解:
#
ConfigFile=./config
ProgramName=./ds4kscript.sh
if [ -f $ConfigFile ]
then
echo "OK" >> /dev/null
else
echo "$ConfigFile not exist!"
exit -1
fi
# 从配置文件中依次获取参数值
sed -n '/LunNumber:/'p $ConfigFile >tmp
lunNumber=`sed 's/LunNumber://' tmp`
echo lunNumber=$lunNumber
sed -n '/ArrayNumber:/'p $ConfigFile >tmp
arrayNumber=`sed 's/ArrayNumber://' tmp`
echo arrayNumber=$arrayNumber
sed -n '/LunName:/'p $ConfigFile >tmp
lunName=`sed 's/LunName://' tmp`
echo lunName=$lunName
sed -n '/Capacity:/'p $ConfigFile >tmp
capacity=`sed 's/Capacity://' tmp`
echo capacity=$capacity
sed -n '/HostGroupName:/'p $ConfigFile >tmp
hostGroupName=`sed 's/HostGroupName://' tmp`
echo hostGroupName=$hostGroupName
sed -n '/HostName:/'p $ConfigFile >tmp
hostName=`sed 's/HostName://' tmp`
echo hostName=$hostName
sed -n '/Port0:/'p $ConfigFile >tmp
port0=`sed 's/Port0://' tmp`
echo port0=$port0
sed -n '/Port1:/'p $ConfigFile >tmp
port1=`sed 's/Port1://' tmp`
echo port1=$port1
sed -n '/HostType:/'p $ConfigFile >tmp
hostType=`sed 's/HostType://' tmp`
echo hostType=$hostType
# 创建 IBM storage manager 使用的脚本中创建 Lun 的部分,并保存为 crtlun.cmd。
if [ -f crtlun.cmd ]
then
rm crtlun.cmd
else
echo "OK" >> /dev/null
fi
x=0
while [ $x -lt $lunNumber ]
do
y=`expr $x % 2`
if [ $y -eq 0 ]
then
echo "create logicalDrive array=$arrayNumber userLabel=\"${lunName}_${x}\"
capacity=$capacity owner=a;" >> crtlun.cmd
else
echo "create logicalDrive array=$arrayNumber userLabel=\"${lunName}_${x}\"
capacity=$capacity owner=b;" >> crtlun.cmd
fi
x=`expr $x + 1`
done
# 创建 IBM storage manager 使用的脚本中创建 host group,host 和 host port 的部分,并保存为 crthost.cmd。
if [ -f crthost.cmd ]
then
rm crthost.cmd
else
echo "OK" >> /dev/null
fi
echo "create hostGroup userLabel=\"$hostGroupName\";" >>crthost.cmd
echo "create host userLabel = \"$hostName\" hostGroup = \"$hostGroupName\";" >>crthost.cmd
echo "create hostPort identifier = \"$port0\" userLabel = \"${hostName}_hba0\"
host = \"$hostName\" hostType = $hostType;" >>crthost.cmd
echo "create hostPort identifier = \"$port1\" userLabel = \"${hostName}_hba1\"
host = \"$hostName\" hostType = $hostType;" >>crthost.cmd
# 创建 IBM storage manager 使用的脚本中映射 Lun 的部分,并保存为 maplun.cmd。
if [ -f maplun.cmd ]
then
rm maplun.cmd
else
echo "OK" >> /dev/null
fi
x=0
while [ $x -lt $lunNumber ]
do
echo "set logicalDrive [\"${lunName}_${x}\"] logicalUnitNumber=$x
hostGroup=\"$hostGroupName\";" >>maplun.cmd
x=`expr $x + 1`
done
# 创建 IBM storage manager 使用的脚本中删除 Lun 映射的部分,并保存为 delmap.cmd。
if [ -f delmap.cmd ]
then
rm delmap.cmd
else
echo "OK" >> /dev/null
fi
x=0
while [ $x -lt $lunNumber ]
do
echo "remove logicalDrive [\"${lunName}_${x}\"] lunMapping
hostGroup=\"$hostGroupName\";" >>delmap.cmd
x=`expr $x + 1`
done
# 创建 IBM storage manager 使用的脚本中删除 Lun 的部分,并保存为 dellun.cmd。
if [ -f dellun.cmd ]
then
rm dellun.cmd
else
echo "OK" >> /dev/null
fi
x=0
while [ $x -lt $lunNumber ]
do
echo "delete logicalDrive [\"${lunName}_${x}\"];" >>dellun.cmd
x=`expr $x + 1`
done
# 创建 IBM storage manager 使用的脚本中删除 host port 的部分,并保存为 delhost.cmd。
if [ -f delhost.cmd ]
then
rm delhost.cmd
else
echo "OK" >> /dev/null
fi
echo "delete hostPort [\"$port0\"];" >>delhost.cmd
echo "delete hostPort [\"$port1\"];" >>delhost.cmd
echo "delete host [\"$hostName\"];" >>delhost.cmd
echo "delete hostGroup [\"$hostGroupName\"];" >>delhost.cmd
# 创建 IBM storage manager 使用的 2 个功能集合脚本,并分别保存为 setup.cmd 和 destroy.cmd。
if [ -f setup.cmd ]
then
rm setup.cmd
else
echo "OK" >> /dev/null
fi
cat crtlun.cmd >>setup.cmd
cat crthost.cmd >>setup.cmd
cat maplun.cmd >>setup.cmd
if [ -f destroy.cmd ]
then
rm destroy.cmd
else
echo "OK" >> /dev/null
fi
cat delmap.cmd >>destroy.cmd
cat delhost.cmd >>destroy.cmd
cat dellun.cmd >>destroy.cmd
总结
从上面可以看出,整个脚本使用的技术不是很复杂,主要是利用 SED 编辑器通过模式匹配从配置文件中提取出所需要的部分,然后从新组织起来,形成一定的符合 IBM storage manager 使用的格式。其中还利用了一些简单的正则表达式,这在很多系统管理的脚本中很常见,可见功能的实效性。当然,作为 SED 这个强大的编辑器,功能远远不止这些,这里也是希望能通过我的一些实践和大家分享一些使用脚本的心得。最终的目的还是提高工作的效率,哪一个管理员或是相关的工程师也不希望总是做一些没有技术含量而且重复性很大的工作,所以脚本以及 SED 编辑器,Awk 等工具都是各位很好的帮手。下面看一下所生成的两个功能集合脚本的内容,体验一下成果的滋味。
setup.cmd
create logicalDrive array=1 userLabel="sunx325b_0" capacity=0.5GB owner=a;
create logicalDrive array=1 userLabel="sunx325b_1" capacity=0.5GB owner=b;
create logicalDrive array=1 userLabel="sunx325b_2" capacity=0.5GB owner=a;
create logicalDrive array=1 userLabel="sunx325b_3" capacity=0.5GB owner=b;
create logicalDrive array=1 userLabel="sunx325b_4" capacity=0.5GB owner=a;
.
.
.
.
create logicalDrive array=1 userLabel="sunx325b_26" capacity=0.5GB owner=a;
create logicalDrive array=1 userLabel="sunx325b_27" capacity=0.5GB owner=b;
create logicalDrive array=1 userLabel="sunx325b_28" capacity=0.5GB owner=a;
create logicalDrive array=1 userLabel="sunx325b_29" capacity=0.5GB owner=b;
create hostGroup userLabel="sunx325b_group";
create host userLabel = "sunx325b" hostGroup = "sunx325b_group";
create hostPort identifier = "210000e08b0e934d" userLabel = "sunx325b_hba0"
host = "sunx325b" hostType = 8;
create hostPort identifier = "210000e08b0e6e50" userLabel = "sunx325b_hba1"
host = "sunx325b" hostType = 8;
set logicalDrive ["sunx325b_0"] logicalUnitNumber=0 hostGroup="sunx325b_group";
set logicalDrive ["sunx325b_1"] logicalUnitNumber=1 hostGroup="sunx325b_group";
set logicalDrive ["sunx325b_2"] logicalUnitNumber=2 hostGroup="sunx325b_group";
set logicalDrive ["sunx325b_3"] logicalUnitNumber=3 hostGroup="sunx325b_group";
set logicalDrive ["sunx325b_4"] logicalUnitNumber=4 hostGroup="sunx325b_group";
.
.
.
.
set logicalDrive ["sunx325b_25"] logicalUnitNumber=25 hostGroup="sunx325b_group";
set logicalDrive ["sunx325b_26"] logicalUnitNumber=26 hostGroup="sunx325b_group";
set logicalDrive ["sunx325b_27"] logicalUnitNumber=27 hostGroup="sunx325b_group";
set logicalDrive ["sunx325b_28"] logicalUnitNumber=28 hostGroup="sunx325b_group";
set logicalDrive ["sunx325b_29"] logicalUnitNumber=29 hostGroup="sunx325b_group";
destroy.cmd
remove logicalDrive ["sunx325b_0"] lunMapping hostGroup="sunx325b_group";
remove logicalDrive ["sunx325b_1"] lunMapping hostGroup="sunx325b_group";
remove logicalDrive ["sunx325b_2"] lunMapping hostGroup="sunx325b_group";
remove logicalDrive ["sunx325b_3"] lunMapping hostGroup="sunx325b_group";
remove logicalDrive ["sunx325b_4"] lunMapping hostGroup="sunx325b_group";
.
.
.
.
remove logicalDrive ["sunx325b_25"] lunMapping hostGroup="sunx325b_group";
remove logicalDrive ["sunx325b_26"] lunMapping hostGroup="sunx325b_group";
remove logicalDrive ["sunx325b_27"] lunMapping hostGroup="sunx325b_group";
remove logicalDrive ["sunx325b_28"] lunMapping hostGroup="sunx325b_group";
remove logicalDrive ["sunx325b_29"] lunMapping hostGroup="sunx325b_group";
delete hostPort ["210000e08b0e934d"];
delete hostPort ["210000e08b0e6e50"];
delete host ["sunx325b"];
delete hostGroup ["sunx325b_group"];
delete logicalDrive ["sunx325b_0"];
delete logicalDrive ["sunx325b_1"];
delete logicalDrive ["sunx325b_2"];
delete logicalDrive ["sunx325b_3"];
delete logicalDrive ["sunx325b_4"];
delete logicalDrive ["sunx325b_5"];
.
.
.
.
delete logicalDrive ["sunx325b_25"];
delete logicalDrive ["sunx325b_26"];
delete logicalDrive ["sunx325b_27"];
delete logicalDrive ["sunx325b_28"];
delete logicalDrive ["sunx325b_29"];
关于作者
齐慧是上海 China Systems & Technology Lab (CSTL)的软件工程师,齐慧的主要工作是测试 IBM storage product 和 open system 例如 SUN server 之间的兼容性。她的工作涉及到 IBM Total Storage Servers,SUN Servers,Veritas Storage Fundation, SUN Cluster,Oracle 等等。你可以通过 qihui@cn.ibm.com 和她联系。