通常,派生清单脚本会从客户机检索信息,并且使用该信息修改基础 AI 清单,以便只为该客户机创建定制 AI 清单。派生清单脚本还可以组合多个部分 AI 清单。最终的派生清单必须是通过验证的完整清单。
派生清单脚本可以是该映像中支持的任何类型的脚本。例如,缺省情况下,映像中包括 ksh93 和 python。如果要使用其他类型的脚本,请确保映像中具有所需的支持。
派生清单脚本可以运行命令来读取系统属性。AI 以 aiuser 角色运行该脚本。aiuser 角色具有非特权用户具有的所有特权以及以下附加特权:
solaris.network.autoconf.read solaris.smf.read.*
aiuser 角色是非特权用户,只不过相比于其他非特权用户,它可以从系统中读取更多信息。aiuser 角色无法更改系统。
有关角色、配置文件和特权的信息,请参见在 Oracle Solaris 11.2 中确保用户和进程的安全 。
除使用命令读取系统属性之外,也可通过下表中显示的环境变量获取客户机属性。
|
要在 AI 清单中添加或修改 XML 元素,请使用 /usr/bin/aimanifest 命令。
要通过 aimanifest 修改的文件至少必须包含以下片段:
对某个 DTD 的 !DOCTYPE 引用,该引用对于所开发的 XML 清单应该有效。
该 DTD 的根元素。
以下示例显示了 AI 清单的最小基础清单文件,其中包括为用于添加该派生清单脚本的安装服务指定 AI DTD 文件:
<!DOCTYPE auto_install SYSTEM "file:///imagepath/auto_install/ai.dtd.1"> <auto_install/>
imagepath 参数的值是以下命令返回的路径,其中 svcname 是将添加该派生清单脚本的安装服务的名称:
$ installadm list -v -n svcname
在执行派生清单脚本中的任何其他 aimanifest 调用之前,请使用 aimanifest 命令的 load 子命令装入基础清单。在安装客户机时,客户机必须可以访问装入的任何文件。例如,可以从目标安装服务中的 imagepath/auto_install/manifest/ 装入清单。
本章中的示例装入文件 /usr/share/auto_install/manifest/default.xml。/usr/share/auto_install/manifest/ 中的清单样例可能与目标安装服务中的清单有所不同。在生产工作中,不应从 /usr/share/auto_install/manifest/ 装入清单。
load 子命令还可用于装入或插入部分清单。
使用 add 子命令添加新元素。使用 set 子命令添加元素属性,或者更改元素或属性值。有关详细信息,请参见 aimanifest(1M) 手册页。手册页和下面的示例脚本提供了使用 aimanifest 命令的示例。
/'"@[]=
根据所用 Shell 的规则,可能需要通过在前面加一个反斜杠 (\) 对引号进行转义,这样 Shell 就不会删除或解释引号。
以下示例返回包含软件包名称 pkg:/entire 的 software_data 元素的操作。在本示例中,pkg:/entire 周围需要使用引号,因为正斜杠是一个特殊字符。如果在 Shell 脚本(如 ksh93 脚本)中调用该命令,则需要使用反斜杠来转义引号。
# /usr/bin/aimanifest get software_data[name=\"pkg:/entire\"]@action
以下部分脚本是一个很好的派生清单脚本范例:
#!/bin/ksh93
SCRIPT_SUCCESS=0
SCRIPT_FAILURE=1
function handler
{
exit $SCRIPT_FAILURE
}
trap handler ERR
/usr/bin/aimanifest load baseAImanifest.xml
# Customize AI manifest. For example:
/usr/bin/aimanifest load -i manifest_fragment.xml
/usr/bin/aimanifest set origin@name file:///net/myserver/myrepo/repo.redist
exit $SCRIPT_SUCCESS
本节介绍如何编写派生清单脚本以确定客户机属性以及如何使用该信息定制 AI 清单。这些示例并不一定包括生成有效 AI 清单所需的全部信息。
要尝试使用这些示例,请执行以下设置步骤:
将 AIM_MANIFEST 环境变量设置为脚本将开发 AI 清单的位置。
针对修改 $AIM_MANIFEST 文件的每个 aimanifest 命令,重新写入该文件。每次结合 load、add、delete 或 set 子命令调用 aimanifest 时都会打开、修改和保存 AIM_MANIFEST 文件。如果未设置 AIM_MANIFEST,aimanifest 命令将失败。
将 AIM_LOGFILE 环境变量设置为脚本可以写入详细信息和错误消息的位置。
aimanifest 命令将子命令名称、参数值以及每个 aimanifest 调用的返回状态记录到屏幕和 $AIM_LOGFILE 文件(如果设置)。
确保 aimanifest 命令在运行脚本的系统上可用。如果 aimanifest 命令不可用,请安装 auto-install-common 软件包。
设置环境变量。这些示例说明了如何使用环境变量来检索客户机相关信息。要尝试使用这些示例,必须为这些环境变量设置值。
使用 AI 安装系统时,Table 10–1 中显示的环境变量具有值,并且可供派生清单脚本使用。
本示例对 AI 清单进行了定制,以便在磁盘大小超过 1 TB 时,仅将目标磁盘的一半用于 Oracle Solaris fdisk 分区。尝试将 SI_DISKSIZE_1 设置为小于 1 TB,然后在该脚本的不同运行中设置为大于 1 TB。此外,需先设置 SI_NUMDISKS 和 SI_DISKNAME_1,然后运行脚本。请注意,该脚本仅用于 x86 客户机,因为指定的分区仅适用于 x86 客户机。
#!/bin/ksh93
SCRIPT_SUCCESS=0
SCRIPT_FAILURE=1
function handler
{
exit $SCRIPT_FAILURE
}
trap handler ERR
/usr/bin/aimanifest load /usr/share/auto_install/manifest/default.xml
# Check that there is only one disk on the system.
if [[ $SI_NUMDISKS -gt "1" ]] ; then
print -u2 "System has too many disks for this script."
exit $SCRIPT_FAILURE
fi
/usr/bin/aimanifest add \
/auto_install/ai_instance/target/disk/disk_name@name $SI_DISKNAME_1
if [[ $SI_DISKSIZE_1 -gt "1048576" ]] ; then
typeset -i PARTN_SIZE=$SI_DISKSIZE_1/2
# Default action is to create.
/usr/bin/aimanifest add \
/auto_install/ai_instance/target/disk[disk_name@name=\"$SI_DISKNAME_1\"]/partition@name 1
/usr/bin/aimanifest add \
/auto_install/ai_instance/target/disk/partition[@name=1]/size@val \
${PARTN_SIZE}mb
else
/usr/bin/aimanifest add \
/auto_install/ai_instance/target/disk[disk_name@name=\"$SI_DISKNAME_1\"]/partition@action \
use_existing_solaris2
fi
exit $SCRIPT_SUCCESS对于 SI_DISKSIZE_1 的值小于或等于 1048576 的客户机,会将以下元素添加到 $AIM_MANIFEST:
<target>
<disk>
<disk_name name="/dev/dsk/c0t0d0s0"/>
<partition action="use_existing_solaris2"/>
</disk>
<!-- <logical> section -->
</target>对于 SI_DISKSIZE_1 的值大于 1048576 的客户机,会将类似如下的元素添加到 $AIM_MANIFEST,具体取决于 SI_DISKSIZE_1 的值:
<target>
<disk>
<disk_name name="/dev/dsk/c0t0d0s0"/>
<partition name="1">
<size val="524288mb"/>
</partition>
</disk>
<!-- <logical> section -->
</target>该命令指定了 disk_name 来添加分区,以避免为分区创建单独的磁盘指定。本示例中的脚本指定该分区位于 $SI_DISKNAME_1 磁盘,而非其他磁盘。如果本示例中的相应行替换为以下行,将无法获得预期的结果:
/usr/bin/aimanifest add \
/auto_install/ai_instance/target/disk/partition@name 1
/usr/bin/aimanifest add \
/auto_install/ai_instance/target/disk/partition[@name=1]/size@val \
${PARTN_SIZE}mb
else
/usr/bin/aimanifest add \
/auto_install/ai_instance/target/disk/partition@action \
use_existing_solaris2该脚本将向您提供以下错误输出,而不是上面显示的输出:
<target>
<disk>
<disk_name name="c0t0d0s0"/>
</disk>
<disk>
<partition name="1">
<size val="524288mb"/>
</partition>
</disk>
</target>
示例 10-2 根据附加磁盘的存在情况指定根池布局本示例对 AI 清单进行了定制,以便在存在第二个磁盘时配置根池的镜像,并在存在第三个磁盘时配置三重镜像。先设置 SI_NUMDISKS 和 SI_DISKNAME_1,然后运行脚本。根据需要设置 SI_DISKNAME_2、SI_DISKNAME_3 以及其他任何变量,具体取决于为 SI_NUMDISKS 设置的值。在 AI 安装期间,将设置这些环境变量并将其用于派生清单脚本。
本示例说明了如何使用 aimanifest 返回路径(–r 选项)。有关返回路径的更多信息,请参见 aimanifest(1M) 手册页。
#!/bin/ksh93
SCRIPT_SUCCESS=0
SCRIPT_FAILURE=1
function handler
{
exit $SCRIPT_FAILURE
}
trap handler ERR
/usr/bin/aimanifest load /usr/share/auto_install/manifest/default.xml
# Use the default if there is only one disk.
if [[ $SI_NUMDISKS -ge 2 ]] ; then
typeset -i disk_num
# Turn on mirroring. Assumes a root zpool is already set up.
vdev=$(/usr/bin/aimanifest add -r \
target/logical/zpool[@name=rpool]/vdev@name mirror_vdev)
/usr/bin/aimanifest set ${vdev}@redundancy mirror
for ((disk_num = 1; disk_num <= $SI_NUMDISKS; disk_num++)) ; do
eval curr_disk="$"SI_DISKNAME_${disk_num}
disk=$(/usr/bin/aimanifest add -r target/disk@in_vdev mirror_vdev)
/usr/bin/aimanifest set ${disk}@in_zpool rpool
/usr/bin/aimanifest set ${disk}@whole_disk true
disk_name=$(/usr/bin/aimanifest add -r \
${disk}/disk_name@name $curr_disk)
/usr/bin/aimanifest set ${disk_name}@name_type ctd
done
fi
exit $SCRIPT_SUCCESS对于具有名为 c0t0d0 和 c0t1d0 的两个磁盘的系统,本示例会输出以下 XML 元素:
<target>
<disk in_vdev="mirror_vdev" in_zpool="rpool" whole_disk="true">
<disk_name name="c0t0d0" name_type="ctd"/>
</disk>
<disk in_vdev="mirror_vdev" in_zpool="rpool" whole_disk="true">
<disk_name name="c0t1d0" name_type="ctd"/>
</disk>
<logical>
<zpool name="rpool" is_root="true">
<vdev name="mirror_vdev" redundancy="mirror"/>
<filesystem name="export" mountpoint="/export"/>
<filesystem name="export/home"/>
<be name="solaris"/>
</zpool>
</logical>
</target>
示例 10-3 在至少存在两个指定大小的磁盘时指定镜像配置本示例对 AI 清单进行了定制,以便在系统至少有两个 200 GB 的磁盘时指定镜像配置。使用发现的前两个至少为 200 GB 的磁盘。先在测试环境中设置 SI_NUMDISKS、SI_DISKNAME_1 和 SI_DISKSIZE_1,然后运行脚本。此外,根据需要设置 SI_DISKNAME_2、SI_DISKSIZE_2 以及其他任何变量,具体取决于为 SI_NUMDISKS 设置的值。在 AI 安装期间,将设置这些环境变量并将其用于派生清单脚本。
本示例说明了如何在存在多个具有相同路径的节点时修改节点。shell 实现使用 aimanifest 的返回路径 (–r) 选项将路径返回到特定节点,然后使用该路径对同一节点做出其他修改。Python 实现说明了如何使用子路径(使用节点路径中的 [])对同一节点做出其他修改。
#!/bin/ksh93
SCRIPT_SUCCESS=0
SCRIPT_FAILURE=1
function handler
{
exit $SCRIPT_FAILURE
}
trap handler ERR
# Find the disks first.
typeset found_1
typeset found_2
typeset -i disk_num
for ((disk_num = 1; disk_num <= $SI_NUMDISKS; disk_num++)) ; do
eval curr_disk="$"SI_DISKNAME_${disk_num}
eval curr_disk_size="$"SI_DISKSIZE_${disk_num}
if [[ $curr_disk_size -ge "204800" ]] ; then
if [ -z $found_1 ] ; then
found_1=$curr_disk
else
found_2=$curr_disk
break
fi
fi
done
# Now, install them into the manifest.
# Let the installer take the default action if two large disks are not found.
/usr/bin/aimanifest load /usr/share/auto_install/manifest/default.xml
if [[ -n $found_2 ]] ; then
# Turn on mirroring.
vdev=$(/usr/bin/aimanifest add -r \
/auto_install/ai_instance/target/logical/zpool/vdev@redundancy mirror)
/usr/bin/aimanifest set ${vdev}@name mirror_vdev
disk=$(/usr/bin/aimanifest add -r \
/auto_install/ai_instance/target/disk@in_vdev mirror_vdev)
disk_name=$(/usr/bin/aimanifest add -r ${disk}/disk_name@name $found_1)
/usr/bin/aimanifest set ${disk_name}@name_type ctd
disk=$(/usr/bin/aimanifest add -r \
/auto_install/ai_instance/target/disk@in_vdev mirror_vdev)
disk_name=$(/usr/bin/aimanifest add -r ${disk}/disk_name@name $found_2)
/usr/bin/aimanifest set ${disk_name}@name_type ctd
fi
exit $SCRIPT_SUCCESS以下脚本是前面 Korn shell 版本的 Python 版本。
#!/usr/bin/python2.6
import os
import sys
from subprocess import check_call, CalledProcessError
SCRIPT_SUCCESS = 0
SCRIPT_FAILURE = 1
def main():
# Find the disks first.
found_1 = ""
found_2 = ""
si_numdisks = int(os.environ["SI_NUMDISKS"])
for disk_num in range(1, si_numdisks + 1):
curr_disk_var = "SI_DISKNAME_" + str(disk_num)
curr_disk = os.environ[curr_disk_var]
curr_disk_size_var = "SI_DISKSIZE_" + str(disk_num)
curr_disk_size = os.environ[curr_disk_size_var]
if curr_disk_size >= "204800":
if not len(found_1):
found_1 = curr_disk
else:
found_2 = curr_disk
break
# Now, write the disk specifications into the manifest.
# Let the installer take the default action if two large disks are not found.
try:
check_call(["/usr/bin/aimanifest", "load",
"/usr/share/auto_install/manifest/default.xml"])
except CalledProcessError as err:
sys.exit(err.returncode)
if len(found_2):
try:
check_call(["/usr/bin/aimanifest", "add",
"target/logical/zpool[@name=rpool]/vdev@redundancy", "mirror"])
check_call(["/usr/bin/aimanifest", "set",
"target/logical/zpool/vdev[@redundancy='mirror']@name", "mirror_vdev"])
check_call(["/usr/bin/aimanifest", "add",
"target/disk/disk_name@name", found_1])
check_call(["/usr/bin/aimanifest", "set",
"target/disk/disk_name[@name='" + found_1 + "']" + "@name_type", "ctd"])
check_call(["/usr/bin/aimanifest", "set",
"target/disk[disk_name@name='" + found_1 + "']" + "@in_vdev", "mirror_vdev"])
check_call(["/usr/bin/aimanifest", "add",
"target/disk/disk_name@name", found_2])
check_call(["/usr/bin/aimanifest", "set",
"target/disk/disk_name[@name='" + found_2 + "']" + "@name_type", "ctd"])
check_call(["/usr/bin/aimanifest", "set",
"target/disk[disk_name@name='" + found_2 + "']" + "@in_vdev", "mirror_vdev"])
except CalledProcessError as err:
sys.exit(err.returncode)
sys.exit(SCRIPT_SUCCESS)
if __name__ == "__main__":
main()
示例 10-4 根据 IP 地址指定要安装的软件包本示例对 AI 清单进行了定制,以便在客户机 IP 地址位于指定范围中时安装一个软件包,以及在客户机 IP 地址在其他范围中时安装不同的软件包。先在测试环境中设置 SI_HOSTADDRESS,然后运行脚本。在 AI 安装期间,将设置该环境变量并将其用于派生清单脚本。
#!/bin/ksh93
SCRIPT_SUCCESS=0
SCRIPT_FAILURE=1
function handler
{
exit $SCRIPT_FAILURE
}
trap handler ERR
/usr/bin/aimanifest load /usr/share/auto_install/manifest/default.xml
# First determine which range the host IP address of the client is in.
echo $SI_HOSTADDRESS | sed 's/\./ /g' | read a b c d
# Assume all systems are on the same class A and B subnets.
# If the system is on class C subnet = 100, then install the /pkg100 package.
# If the system is on class C subnet = 101, then install the /pkg101 package.
# Otherwise, do not install any other additional package.
if ((c == 100)) ; then
/usr/bin/aimanifest add \
software/software_data[@action='install']/name pkg:/pkg100
fi
if ((c == 101)) ; then
/usr/bin/aimanifest add \
software/software_data[@action='install']/name pkg:/pkg101
fi
exit $SCRIPT_SUCCESS
示例 10-5 指定目标磁盘必须至少为特定大小本示例对 AI 清单进行了定制,以便只在至少为 50 GB 的磁盘上进行安装。忽略更小的磁盘。先在测试环境中设置 SI_NUMDISKS、SI_DISKNAME_1 和 SI_DISKSIZE_1,然后运行脚本。此外,根据需要设置 SI_DISKNAME_2、SI_DISKSIZE_2 以及其他任何变量,具体取决于为 SI_NUMDISKS 设置的值。在 AI 安装期间,将设置这些环境变量并将其用于派生清单脚本。
#!/bin/ksh93
SCRIPT_SUCCESS=0
SCRIPT_FAILURE=1
function handler
{
exit $SCRIPT_FAILURE
}
trap handler ERR
/usr/bin/aimanifest load /usr/share/auto_install/manifest/default.xml
typeset found
typeset -i disk_num
for ((disk_num = 1; disk_num <= $SI_NUMDISKS; disk_num++)) ; do
eval curr_disk="$"SI_DISKNAME_${disk_num}
eval curr_disk_size="$"SI_DISKSIZE_${disk_num}
if [[ $curr_disk_size -ge "512000" ]] ; then
found=$curr_disk
/usr/bin/aimanifest add \
/auto_install/ai_instance/target/disk/disk_name@name $found
break
fi
done
if [[ -z $found ]] ; then
exit $SCRIPT_FAILURE
fi
exit $SCRIPT_SUCCESS
示例 10-6 添加系统配置文件
有时,需要针对每个客户机更改系统配置。此时不必在每个客户机的 AI 服务器上创建单独的系统配置文件,而是配置一个用于创建配置文件的派生清单脚本。配置文件必须存储在 /system/volatile/profile 中,以便安装服务能够使用它。在此示例中,重新配置客户机时,将使用本地缺省路由器的设置。
ROUTER-CONFIG=/system/volatile/profile/router-config.xml
ROUTER=`netstat -rn | grep "^default" | awk '{print $2}'`
cat<<EOF>${ROUTER-CONFIG}
<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<service_bundle type="profile" name="router">
<service name="network/install" version="1" type="service">
<instance name="default" enabled="true">
<property_group name="install_ipv4_interface" type="application">
<propval name="default_route" type="net_address_v4" value="${ROUTER}"/>
</property_group>
</instance>
</service>
</service_bundle>
EOF
示例 10-7 清单规范错误的脚本本示例中的脚本有错误。
#!/bin/ksh93
SCRIPT_SUCCESS=0
SCRIPT_FAILURE=1
function handler
{
exit $SCRIPT_FAILURE
}
trap handler ERR
/usr/bin/aimanifest load /usr/share/auto_install/manifest/default.xml
/usr/bin/aimanifest set \
software[@type="IPS"]/software_data/name pkg:/driver/pcmcia
/usr/bin/aimanifest set \
software/software_data[@name=pkg:/driver/pcmcia]@action uninstall
return $SCRIPT_SUCCESS本示例在写入 $AIM_MANIFEST 时存在三个问题。
aimanifest 的 set 子命令可以更改现有元素或属性的值,或创建新属性。set 子命令无法创建新元素。第一个 set 子命令尝试修改清单中的现有软件包名称,而不是创建新软件包名称。如果清单中已存在多个软件包名称,则会造成多义性错误,因为无法确定要修改哪个软件包。本示例中的第一个 set 子命令本应是 add 子命令。
在本示例的第二个 set 子命令中,以前置的 @ 符号指定值为 pkg:/driver/pcmcia 的元素 name。尽管属性值使用前置的 @ 符号指定,但这对元素值并不适用。
值 pkg:/driver/pcmcia 应括在引号中。带斜杠或其他特殊字符的值必须用引号括起来。
在本示例中,以下行应替换两个 set 行:
/usr/bin/aimanifest add \
software[@type="IPS"]/software_data@action uninstall
/usr/bin/aimanifest add \
software/software_data[@action=uninstall]/name pkg:/driver/pcmcia以上两个 add 子命令将以下行添加到正在编写的清单的 software 部分的末尾:
<software_data action="uninstall"> <name>pkg:/driver/pcmcia</name> </software_data>
要测试派生清单脚本,请在类似于 AI 安装环境的环境中运行此脚本。
为要修改的脚本设置基础 AI 清单。
确保脚本中的第一个 aimanifest 命令是 aimanifest load 命令。确保装入的文件中包含 <!DOCTYPE> 定义,该定义指定了对目标安装服务进行 AI 清单验证时使用的相应 DTD。以下示例显示了 AI 清单的最小基础清单文件,其中包括为用于添加该派生清单脚本的安装服务指定 AI DTD 文件:
<!DOCTYPE auto_install SYSTEM "file:///imagepath/auto_install/ai.dtd.1"> <auto_install/>
imagepath 参数的值是以下命令返回的路径,其中 svcname 是将添加该派生清单脚本的安装服务的名称:
$ installadm list -v -n svcname| grep Image
将 AIM_MANIFEST 设置为脚本将开发 AI 清单的位置。该位置必须可由非特权用户 aiuser 写入。
将 AIM_LOGFILE 设置为脚本可以写入详细信息和错误消息的位置。该位置必须可由非特权用户 aiuser 写入。
确保 aimanifest 命令在测试脚本的系统上可用。如果 aimanifest 命令不可用,请安装 auto-install-common 软件包。
在测试环境中为环境变量设置值,这些值表示将使用该派生清单脚本安装的客户机系统。样例文件 /usr/share/auto_install/derived_manifest_test_env.sh 可用作模板。根据需要更改值。
在 AI 执行安装时,Table 10–1 中显示的环境变量具有值,并且可供派生清单脚本使用。
确保您可以承担 root 角色。通过 root 角色,您可以在不指定口令的情况下承担 aiuser 角色。
$ su Password: # su aiuser -c ./script #
AI 以 aiuser 角色执行派生清单脚本。要模拟 AI 安装环境,请承担 aiuser 角色以运行脚本。如果以具有与 aiuser 角色不同的特权的用户身份运行脚本,则脚本中的某些操作可能会得到不同的结果。
对生成的清单使用 validate 子命令。
$ /usr/bin/aimanifest validate
仅当验证失败时才显示消息。
预定的客户机系统可能与可在其中测试派生清单脚本的 AI 服务器或其他系统大为不同。在脚本中调用的命令可能不可用,或是具有不同行为的不同版本。系统可能是不同的体系结构,或具有不同数目和大小的磁盘。按照所述在测试环境中设置环境变量,可处理其中的一些不同之处。
本过程介绍如何在一个预定客户机系统上测试派生清单脚本而不运行完整安装过程。
以“文本安装程序和命令行”模式,在该客户机系统中引导 AI 映像。
使用 wget 或 sftp 从 AI 服务器复制脚本。
使用以下方法之一调试脚本:
使用以下命令在测试模式中运行 AI:
$ auto-install -m script -i
检查 AI 日志文件 /system/volatile/install_log。日志文件应包含以下行以指示脚本验证:
Derived Manifest Module: XML validation completed successfully
如果进行了更改,请将脚本复制回 AI 服务器。