Vyatta専用コマンドを深堀りしてみた。¶
前回のエントリ で書いた通り、configureコマンドやsetコマンドはシェルスクリプトでは使えませんでした。単にVyattaを運用するだけなら、そのまま ${vyatta_sbindir}/my_* コマンドを使えば良いのでしょう。でも何故使えなかったのでしょうか。なんでそのままにしておくのは気持ち悪くて、夜もぐっすり眠れません。精神衛生上よろしくありませんね。
ですので、このモヤモヤを解消するため、オペレーションモード、設定モードについてそれぞれ調べてみました。
オペレーションモードの専用コマンドを探る。¶
まず、aliasコマンドを実行してみると分かります。
$ alias
alias add='_vyatta_op_run add'
alias clear='_vyatta_op_run clear'
alias clone='_vyatta_op_run clone'
alias configure='_vyatta_op_run configure'
alias connect='_vyatta_op_run connect'
alias copy='_vyatta_op_run copy'
alias debug='_vyatta_op_run debug'
alias delete='_vyatta_op_run delete'
alias disconnect='_vyatta_op_run disconnect'
alias format='_vyatta_op_run format'
alias generate='_vyatta_op_run generate'
alias init-floppy='_vyatta_op_run init-floppy'
alias install-image='_vyatta_op_run install-image'
alias install-system='_vyatta_op_run install-system'
alias ls='ls --color=auto'
alias no='_vyatta_op_run no'
alias ping='_vyatta_op_run ping'
alias ping6='_vyatta_op_run ping6'
alias reboot='_vyatta_op_run reboot'
alias release='_vyatta_op_run release'
alias remove='_vyatta_op_run remove'
alias rename='_vyatta_op_run rename'
alias renew='_vyatta_op_run renew'
alias reset='_vyatta_op_run reset'
alias restart='_vyatta_op_run restart'
alias set='_vyatta_op_run set'
alias show='_vyatta_op_run show'
alias shutdown='_vyatta_op_run shutdown'
alias telnet='_vyatta_op_run telnet'
alias terminal='_vyatta_op_run terminal'
alias traceroute='_vyatta_op_run traceroute'
alias traceroute6='_vyatta_op_run traceroute6'
alias undebug='_vyatta_op_run undebug'
alias update='_vyatta_op_run update'
“_vyatta_op_run hoge”の形でaliasが設定されているのは全てVyatta専用のコマンドです。_vyatta_op_runは、/etc/bash_completion.d/vyatta-op-runで定義されている関数です。
_vyatta_op_run ()
{
local -i estat
local tpath=$vyatta_op_templates
local restore_shopts=$( shopt -p extglob nullglob | tr \\n \; )
shopt -s extglob nullglob
_vyatta_op_last_comp=${_vyatta_op_last_comp_init}
false; estat=$?
i=1
for arg in "$@"
do
if [ -f "$tpath/$arg/node.def" ] ; then
tpath+=/$arg
elif [ -f $tpath/node.tag/node.def ] ; then
tpath+=/node.tag
else
echo "Invalid command" >&2
eval $restore_shopts
return 1
fi
let "i+=1"
done
local run_cmd=$(_vyatta_op_get_node_def_field $tpath/node.def run)
local ret=0
if [ -n "$run_cmd" ]; then
if [[ -t 1 && "$1" == "show" && \
! $run_cmd =~ ^\(LESSOPEN=\|less\|pager\|tail\|/opt/vyatta/bin/vyatta-tshark-interface-port.pl\).* ]] ; then
eval "($run_cmd) | ${VYATTA_PAGER:-cat}"
else
eval "$run_cmd"
fi
else
echo "Incomplete command" >&2
ret=1
fi
eval $restore_shopts
return $ret
}
この中の”$run_cmd”が実際に実行するvyatta用のコマンドが設定されます。$run_cmdが、”show”だった場合、showコマンドで設定やステータスの情報を表示し、それ以外の場合は、$tpath/$arg/node.defで定義されているコマンドを実行します。このコマンドの引数などが不完全な場合は、”Incomplete command”と実行される、というわけです。$tpathは、$vyatta_op_templatesが代入されていますがこの変数は入れ子になっており、実際に実行するコマンドは/opt/vyatta/share/vyatta-op/templates/ ${arg}として、実行されるコマンドの処理内容は/opt/vyatta/share/vyatta-op/templates/${arg}/node .defに定義されています。例えば、 show interfaces
とするとインタフェースの設定状況を確認できますが、これは、templates/show/interfaces/node.defで定義されており、その内容は
help: Show network interface information
run: ${vyatta_bindir}/vyatta-show-interfaces.pl --action=show-brief
となっています。この場合は
help: show interfacesコマンドのヘルプメッセージ
run: show interfacesコマンドが実行する内容( ${vyatta_bindir}/vyatta -show-interfaces.pl –action=show-brief)
というワケです。
なので、オペレーションモードのコマンドをシェルスクリプトにする場合は、シェルスクリプト内でaliasを使えるように、”expand_aliases”を有効にしてやり/etc/bash_completion.d/vyatta-opを読み込みんでやると、オペレーションモードと同じコマンドが使えるようになります。
#!/bin/vbash
shopt -s expand_aliases
. /etc/bash_completion.d/vyatta-op
show interfaces
または、下記のようにalias展開前のコマンドを記述して
#!/bin/vbash
. /etc/bash_completion.d/vyatta-op-run
_vyatta_op_run show interfaces
とするか、node.defのrunで設定されている実行コマンドを記述して
#!/bin/sh
${vyatta_bindir}/vyatta-show-interfaces.pl --action=show-brief
とすればシェルスクリプトでもオペレーションモードのコマンドを使えるようになります。ただし、設定モードに変更するために、
_vyatta_op_run configure
と記述してスクリプトを実行すると、対話形式で設定モードに切り替わってしまうので、その後ろに書いている設定モードのコマンドは実行されません。
オペレーションモードのtabキーの動きを探る。¶
vbashでは、tab補完が効きますが、何も入力していない状態でtabキーを一回押すと、
add debug install-image release set traceroute6
clear delete install-system remove show undebug
clone disconnect no rename shutdown update
configure format ping renew telnet
connect generate ping6 reset terminal
copy init-floppy reboot restart traceroute
のように実行可能なVyatta専用のコマンドが表示されます。これは、/opt/vyatta/share/vyatta-op/templates/以下をlsで見た場合と同じです。
$ ls /opt/vyatta/share/vyatta-op/templates/
add connect disconnect install-image ping6 rename set terminal update
clear copy format install-system reboot renew show traceroute
clone debug generate no release reset shutdown traceroute6
configure delete init-floppy ping remove restart telnet undebug
再度tabキーを押すと、各コマンドの概要が表示されます。
Possible completions:
add Add an object to a service
clear Clear system information
clone Clone an object
configure Enter configure mode
connect Establish a connection
copy Copy data
debug Enable debugging of specified routing protocol
delete Delete a file
disconnect Take down a connection
format Format a device
generate Generate an object
init-floppy Format and prepare a floppy to save the config.boot file
install-image Install new system image to hard drive
install-system
Install system to hard drive
no Disable or reset operational variable
ping Send Internet Control Message Protocol (ICMP) echo request
ping6 Send IPv6 Internet Control Message Protocol (ICMP) echo request
reboot Reboot the system
release Release specified variable
remove Remove an object from service
rename Re-name something.
renew Renew specified variable
reset Reset a service
restart Restart a service
set Set system or shell options
show Show system information
shutdown Shutdown the system
telnet Telnet to <hostname|IPv4 address>
terminal Control terminal behaviors
traceroute Track network path to <hostname|IPv4 address>
traceroute6 Track network path to <hostname|IPv6 address>
undebug Disable specified debugging
update Run an update command
これは、node.defの、”help:”で設定されている内容が表示されます。
設定モードの専用コマンドを探る。¶
一方、設定モードで使用するcommitやsave, loadコマンドなどは、/etc/bash_completion.d/vyatta-cfgで定義されています。
$ grep '()' /etc/bash_completion.d/vyatta-cfg | egrep -v '^\s|declare|vyatta|get|print|generate|reset|really' | more
show ()
commit ()
commit-confirm ()
confirm ()
compare ()
save ()
reboot ()
rollback ()
shutdown ()
load ()
merge ()
top ()
edit ()
up ()
exit ()
run ()
loadkey()
オペレーションモードと同様にtabキーを押すと、コマンドが表示されます。
comment commit-confirm confirm delete edit load merge rollback save show
commit compare copy discard exit loadkey rename run set
tabキーもう一回押して表示されるhelpは、オペレーションモードとは異なり、/etc/bash_completion.d/vyatta-cfgの中で変数_get_help_text_helpsに設定されています。
_get_help_text_helps=( \
"Confirm prior commit-confirm" \
"Add comment to this configuration element" \
"Commit the current set of changes" \
"Commit the current set of changes with 'confirm' required" \
"Compare configuration revisions" \
"Copy a configuration element" \
"Delete a configuration element" \
"Discard uncommitted changes" \
"Edit a sub-element" \
"Exit from this configuration level" \
"Load configuration from a file and replace running configuration" \
"Load user SSH key from a file" \
"Load configuration from a file and merge running configuration" \
"Rename a configuration element" \
"Rollback to a prior config revision (requires reboot)" \
"Run an operational-mode command" \
"Save configuration to a file" \
"Set the value of a parameter or create a new element" \
"Show the configuration (default values may be suppressed)" \
)
設定モードで使えるコマンドは、この/etc/bash_completion.d/vyatta-cfgで定義されているコマンド以外に、aliasで設定されているものもあります。
$ configure
# alias
alias comment='/opt/vyatta/sbin/my_comment'
alias copy='/opt/vyatta/sbin/my_copy'
alias delete='/opt/vyatta/sbin/my_delete'
alias discard='/opt/vyatta/sbin/my_discard'
alias ls='ls --color=auto'
alias rename='/opt/vyatta/sbin/my_rename'
alias set='/opt/vyatta/sbin/my_set'
[edit]
先ほどのmy_setコマンドが設定されていることが分かります。ここで、オペレーションモードの時と同じように、
#!/bin/vbash
shopt -s expand_aliases
. /etc/bash_completion.d/vyatta-cfg
set interfaces ethernet eth0 description hoge
としても、残念ながら/etc/bash_completion.d/vyatta-cfgの読み込み時に、
# ./test.sh
/etc/bash_completion.d/vyatta-cfg: line 888: bind: warning: line editing not enabled
/etc/bash_completion.d/vyatta-cfg: line 889: bind: warning: line editing not enabled
/etc/bash_completion.d/vyatta-cfg: line 890: bind: warning: line editing not enabled
/etc/bash_completion.d/vyatta-cfg: line 892: bind: warning: line editing not enabled
/etc/bash_completion.d/vyatta-cfg: line 893: bind: warning: line editing not enabled
[edit]
のようにコケてしまいます 1 。オペレーションモードでこのスクリプトを実行するとwarningは出ませんがやはり設定はできていません。 前回のエントリ のように素直に ${vyatta_sbindir}/my_* コマンドを使うのがよいでしょう。
各レベルのパラメータの定義を探る。¶
オペレーションモードのコマンドを定義していたのが/opt/vyatta/share/vyatta-op/templates/以下でしたが、設定モードで使う各レベルのパラメータは/opt/vyatta/share/vyatta-cfg/templates/の下で定義されています。
VyattaはDebianベースのディストロです。Vyattaの最新版の6.3はDebian GNU/Linux Squeezeのi386, amd64がベースになっており、Vyatta独自のソフトウェアもDebianパッケージとして提供されています。前者はvyatta-opパッケージで、後者はvyatta-cfgパッケージで基本的に提供されています。vyatta-cfgパッケージで提供されているテンプレートはinterfacesだけでsystem,serviceなどのテンプレートは他のパッケージ(systemならvyatta-cfg-system, NATならvyatta-natなど)で提供されています。例えば、ホスト名の設定は、
# set system host-name hoge
と設定しますが、これはvyatta-cfg-systemパッケージのtemplates/system/host-name/node.defで定義されています。これの中を見てみると、
type: txt
help: Set system host name (default: vyatta)
default: "vyatta"
syntax:expression: pattern $VAR(@) "^[[:alpha:]][-.[:alnum:]]*[[:alnum:]]$"
; "invalid host name $VAR(@)"
update: sudo sh -c " \
hostname '$VAR(@)'
echo '$VAR(@)' > /etc/hostname
touch /etc/hosts
sed -i '/^127.0.1.1/d' /etc/hosts
echo -e \"127.0.1.1\t $VAR(@)\t #vyatta entry\" >> /etc/hosts
if [ x$VAR(../domain-name/@) != x ]; then
echo -e \"127.0.1.1\t $VAR(@).$VAR(../domain-name/@)\t #vyatta entry\" \
>> /etc/hosts
echo \"$VAR(@).$VAR(../domain-name/@)\" > /etc/mailname
else
echo \"$VAR(@)\" > /etc/mailname
fi"
delete: sudo sh -c " \
echo 'vyatta' > /etc/hostname
hostname 'vyatta'
touch /etc/hosts
sed -i '/^127.0.1.1/d' /etc/hosts
echo -e \"127.0.1.1\t vyatta\t #vyatta entry\" >> /etc/hosts
if [ x$VAR(../domain-name/@) != x ]; then
echo -e \"127.0.1.1\t vyatta.$VAR(../domain-name/@)\t #vyatta entry\" \
>> /etc/hosts
echo \"vyatta.$VAR(../domain-name/@)\" > /etc/mailname
else
echo \"vyatta\" > /etc/mailname
fi"
となっています。この内容は、
type: とりうるパラメータの種類(ここではtxt)
help: コマンドのヘルプ
default: デフォルト値(デフォルトではホスト名はvyatta)
sytax:expression: 書式のパターン(ホスト名の先頭一文字目は半角英字、2文字目以降は半角英数もしくはハイフン、またはピリオド、最後の文字は半角英数を許可)
update: ホスト名更新時に実行される処理(/etc/hostname, /etc/hosts, /etc/mailnameを指定したホスト名およびドメイン名があればそれで更新)
delete: ホスト名削除時に実行される処理(update時に更新されるファイルをホスト名を”vyatta”として更新)
ですので、オペレーションモードでのコマンドの定義と基本的には同じだということが分かります。
${vyatta_sbindir}/my_* コマンドを探る。¶
それでは、先ほどの my_* コマンドについてもう少し突っ込んで見てみます。これらのコマンドの実体は ${vyatta_sbindir}/my_cli_bin へのシンボリックリンクになっています。
$ ls -l ${vyatta_sbindir}/my*
-rwxr-xr-x 1 root root 19512 Jul 21 09:31 /opt/vyatta/sbin/my_cli_bin
-rwxr-xr-x 1 root root 32416 Jul 21 09:31 /opt/vyatta/sbin/my_cli_shell_api
lrwxrwxrwx 1 root root 10 Jul 21 16:37 /opt/vyatta/sbin/my_comment -> my_cli_bin
lrwxrwxrwx 1 root root 10 Jul 21 16:37 /opt/vyatta/sbin/my_commit -> my_cli_bin
lrwxrwxrwx 1 root root 10 Jul 21 16:37 /opt/vyatta/sbin/my_copy -> my_cli_bin
lrwxrwxrwx 1 root root 10 Jul 21 16:37 /opt/vyatta/sbin/my_delete -> my_cli_bin
lrwxrwxrwx 1 root root 10 Jul 21 16:37 /opt/vyatta/sbin/my_discard -> my_cli_bin
lrwxrwxrwx 1 root root 10 Jul 21 16:37 /opt/vyatta/sbin/my_move -> my_cli_bin
lrwxrwxrwx 1 root root 10 Jul 21 16:37 /opt/vyatta/sbin/my_rename -> my_cli_bin
lrwxrwxrwx 1 root root 10 Jul 21 16:37 /opt/vyatta/sbin/my_set -> my_cli_bin
:command:`${vyatta_sbindir}/my_cli_bin` コマンド自体は、ELF形式の実行ファイルで、my_setコマンドやmy_commitコマンドなどのシンボリックリンクも含め、これはvyatta-cfgパッケージによって提供されています。
$ dpkg -S ${vyatta_sbindir}/my_cli_bin
vyatta-cfg: /opt/vyatta/sbin/my_cli_bin
このバイナリパッケージに含まれているドキュメントは、/usr/share/doc/vyatta-cfg/READMEくらいですが、このファイルには
This package has the Vyatta configuration system, including the configuration back-end, the base configuration templates, and the config-mode CLI completion mechanism.
と書かれています。では、vyatta-cfgパッケージのソースコードを見てみます。
apt-get source vyatta-cfg、じゃあないの?!¶
前述のとおりVyattaはDebianベースなので、
$ apt-get source vyatta-cfg
でソースパッケージを取得しよう!と思うかもしれません。が、デフォルトではdeb-srcのAPT Lineが無いのでできません。そこで、デフォルトで設定されている
deb http://packages.vyatta.com/vyatta stable main # community #
をコピーして、
deb-src http://packages.vyatta.com/vyatta stable main
を設定しても、残念ながらリポジトリにはソースパッケージは置いてないのでapt-get updateがコケます。困ってしまいましたね。
Vyattaのソースコードの入手方法。¶
これもちゃんと ドキュメントに記述があります 。ソースコードを入手するにはbuild-src.gitリポジトリをgit cloneを行います。そして、今回必要なvyatta-cfgパッケージのソースコードはsubmoduleとして入手します。
$ git clone http://git.vyatta.com/build-iso.git
$ cd build-iso
$ git submodule init
(snip)
Submodule 'pkgs/vyatta-cfg' (http://git.vyatta.com/vyatta-cfg.git) registered for path 'pkgs/vyatta-cfg'
(snip)
submoduleの初期化後、submodule updateでpkg/vyatta-cfgリポジトリのコピーを行います。
$ git submodule update pkgs/vyatta-cfg
Cloning into 'pkgs/vyatta-cfg'...
Submodule path 'pkgs/vyatta-cfg': checked out '55dc3e317c138286de6353c21ab47c91fca9a2f4'
git submodule updateが完了すると、HEADがcheckoutされます。
$ cd pkgs/vyatta-cfg
$ git log
commit 55dc3e317c138286de6353c21ab47c91fca9a2f4
Merge: 02a2145 0b582e0
Author: rbalocca <rbalocca@vyatta.com>
Date: Fri Dec 26 09:35:12 2008 -0800
Merge branch 'islavista'
(snip)
$ ls
AUTHORS COPYING ChangeLog Makefile.am NEWS README configure.ac debian etc scripts src templates
なお、単にソースコードを見るだけなら、gitweb経由で VyattaのGitリポジトリ は公開されています。 vyatta-cfgもその中で公開 されています。
my_cli_binのソースコードを見てみる。¶
最新のVyattaのリリースのバージョンはset versionコマンドで確認すると、VC6.3-2011.07.21だと分かります。
$ show version
Version: VC6.3-2011.07.21
(snip)
vyatta-cfgのリポジトリのtagを確認するとVC6.3-2011.07.21にはamd64とi386とがあります。
$ git tag
(snip)
vyatta/VC6.3-2011.07.21/amd64
vyatta/VC6.3-2011.07.21/i386
vyatta/VC6.3-2011.10.04/amd64
vyatta/VC6.3-2011.10.04/i386
タグvyatta/VC6.3-2011.07.21/amd64をまずチェックアウトします。
$ git checkout vyatta/VC6.3-2011.07.21/amd64
Note: checking out 'vyatta/VC6.3-2011.07.21/amd64'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b new_branch_name
HEAD is now at 64d54e8... 0.99.8+napa6
my_cli_binをgrepすると、src/cli_bin.cppがソースコードだと分かります。
$ git grep my_cli_bin
Makefile.am:sbin_PROGRAMS += src/my_cli_bin
Makefile.am:src_my_cli_bin_SOURCES = src/cli_bin.cpp
Makefile.am: $(LN_S) my_cli_bin my_set; \
Makefile.am: $(LN_S) my_cli_bin my_delete; \
Makefile.am: $(LN_S) my_cli_bin my_rename; \
Makefile.am: $(LN_S) my_cli_bin my_copy; \
Makefile.am: $(LN_S) my_cli_bin my_comment; \
Makefile.am: $(LN_S) my_cli_bin my_discard; \
Makefile.am: $(LN_S) my_cli_bin my_move; \
Makefile.am: $(LN_S) my_cli_bin my_commit
debian/vyatta-cfg.postinst.in:for bin in my_cli_bin my_cli_shell_api; do
これを見ると実行するコマンドのパスのbasenameが、*op_bin_name配列の要素にマッチすれば、その機能が実行される、ということが分かります。
static int op_idx = -1;
static const char *op_bin_name[] = {
"my_set",
"my_delete",
"my_activate",
"my_deactivate",
"my_rename",
"my_copy",
"my_comment",
"my_discard",
"my_move",
"my_commit",
NULL
};
static const char *op_Str[] = {
"Set",
"Delete",
"Activate",
"Deactivate",
"Rename",
"Copy",
"Comment",
"Discard",
"Move",
"Commit",
NULL
};
static const char *op_str[] = {
"set",
"delete",
"activate",
"deactivate",
"rename",
"copy",
"comment",
"discard",
"move",
"commit",
NULL
};
(snip)
#define OP_Str op_Str[op_idx]
#define OP_str op_str[op_idx]
#define OP_need_cfg_node_args op_need_cfg_node_args[op_idx]
#define OP_use_edit_level op_use_edit_level[op_idx]
(snip)
static void
doSet(Cstore& cstore, const Cpath& path_comps)
{
if (!cstore.validateSetPath(path_comps)) {
bye("invalid set path\n");
}
if (!cstore.setCfgPath(path_comps)) {
bye("set cfg path failed\n");
}
}
(snip)
typedef void (*OpFuncT)(Cstore& cstore,
const Cpath& path_comps);
OpFuncT OpFunc[] = {
&doSet,
&doDelete,
&doActivate,
&doDeactivate,
&doRename,
&doCopy,
&doComment,
&doDiscard,
&doMove,
&doCommit,
NULL
};
int
main(int argc, char **argv)
{
int i = 0;
while (op_bin_name[i]) {
if (strcmp(basename(argv[0]), op_bin_name[i]) == 0) {
op_idx = i;
break;
}
++i;
}
(snip)
Cstore *cstore = Cstore::createCstore(OP_use_edit_level);
Cpath path_comps(const_cast<const char **>(argv + 1), argc - 1);
// call the op function
OpFunc[op_idx](*cstore, path_comps);
delete cstore;
exit(0);
}
masterブランチは古いので要注意。¶
ちなみに、vyatta-cfgのリポジトリはmasterブランチが結構古いままです。前述のとおり、2008年12月26日のものがHEADになっています。なので git submodule update直後にそのままソースコードを見ても見つかりません。git logで確認すると2010年7月28日にsrc/cli_bin.cppが初めてコミットされているのが分かりますね。気をつけましょう。
$ git log --reverse src/cli_bin.cpp
commit 639c835bc2730a4fbffd915f5b2028a68375ee7a
Author: An-Cheng Huang <ancheng@vyatta.com>
Date: Wed Jul 28 14:30:32 2010 -0700
add new cstore library
まとめ¶
以上をまとめると、オペレーションモードでは次の方法でシェルスクリプトにすることができます。
expand_aliasesを有効にし、/etc/bash_completion.d/vyatta-opを読み込むことで、Vyattaのコマンドをそのまま使う
もしくは/etc/bash_completion.d/vyatta-op-runを読み込み、_vyatta_op_runの引数としてVyattaのコマンドを使う
設定モードでは、
/etc/bash_completion.d/vyatta-cfgを読み込むだけではダメ
${vyatta_sbindir}/my_cli_bin へのsymlinkになっている、 ${vyatta_sbindir}/my_cli_bin コマンドを使う
ということで、これでシェルスクリプトで、快適なVyattaを自動化した生活を送れるようになれますね。
- 1
warningですが、実際に設定されていません。