日本語を含むKicstart/PreseedファイルをCobblerで扱おうとするとエラーが出るので、どうにかならんものかと試行錯誤したのでメモ
cobblerのインストール方法は、今回は省略します。
準備(ざっくり書きます)
- インストーラのlinuxカーネルと初期イメージ(initramfs)を取得
- cobblerにdistroとして登録
$cobbler distro add --name="test" --kernel="/opt/linux-kern" --initrd="/opt/initrd"
- kickstart/preseedファイルを作成(今回はubuntuを想定してpreseedファイル)
#テストコメント <= (注意)コメントが日本語
#サンプルなので、とりあえずこれだけ
d-i debian-installer/locale string en_US
d-i console-setup/ask_detect boolean false
d-i keyboard-configuration/layoutcode string us
d-i keyboard-configuration/variantcode string
- profileの登録
$cobbler profile add --name="test-profile" --distro="test" --kickstart="test_preseed.seed"
で日本語付きのkickstart/preseedファイルを指定したprofileを作成する
コマンドでpreseedファイルを確認しようとしてみる
cobblerのAPIを叩いて確認をしてもいいですが、手っ取り早くコマンドで、
$cobbler profile getks --name test-profile
# This kickstart had errors that prevented it from being rendered correctly.
# The cobbler.log should have information relating to this failure.
この通り、kickstart/preseedファイルに日本語が混じると、エラーが出てファイルが表示されません。ログを見ます
Wed Apr 29 14:01:05 2015 - INFO | generate_kickstart
Wed Apr 29 14:01:05 2015 - INFO | Exception occured: <type 'exceptions.UnicodeDecodeError'>
Wed Apr 29 14:01:05 2015 - INFO | Exception value: 'ascii' codec can't decode byte 0xe3 in position 181: ordinal not in range(128)
Wed Apr 29 14:01:05 2015 - INFO | Exception Info:
File "/usr/lib/python2.7/dist-packages/cobbler/remote.py", line 1025, in generate_kickstart
return self.api.generate_kickstart(profile,system)
File "/usr/lib/python2.7/dist-packages/cobbler/api.py", line 684, in generate_kickstart
return self.kickgen.generate_kickstart_for_profile(profile)
File "/usr/lib/python2.7/dist-packages/cobbler/kickgen.py", line 311, in generate_kickstart_for_profile
return self.generate_kickstart(profile=g)
File "/usr/lib/python2.7/dist-packages/cobbler/kickgen.py", line 289, in generate_kickstart
data = self.templar.render(raw_data, meta, None, obj)
File "/usr/lib/python2.7/dist-packages/cobbler/templar.py", line 116, in render
data_out = self.render_cheetah(raw_data, search_table, subject)
File "/usr/lib/python2.7/dist-packages/cobbler/templar.py", line 201, in render_cheetah
t = Template(source=raw_data, searchList=[search_table], compilerSettings={'useStackFrame':False})
File "DynamicallyCompiledCheetahTemplate.py", line 58, in __init__
File "_etc_cobbler_cheetah_macros.py", line 58, in __init__
File "/usr/lib/python2.7/dist-packages/Cheetah/Template.py", line 1259, in __init__
self._compile(source, file, compilerSettings=compilerSettings)
File "/usr/lib/python2.7/dist-packages/Cheetah/Template.py", line 1553, in _compile
keepRefToGeneratedCode=True)
File "/usr/lib/python2.7/dist-packages/cobbler/template_api.py", line 127, in compile
return Cheetah.Template.Template.compile(*args, **kwargs)
File "/usr/lib/python2.7/dist-packages/Cheetah/Template.py", line 740, in compile
settings=(compilerSettings or {}))
File "/usr/lib/python2.7/dist-packages/Cheetah/Compiler.py", line 1579, in __init__
source = unicode(source)
ASCIIじゃ、デコードできないよ!って怒られているように見える。
どうやら、cobblerでは、kickstart/preseedファイルは、Cheetahというテンプレートエンジンで解釈されてからユーザに表示されているらしい <= おさらい
Cheetahでencodeをutf-8とか指定して、読み込ませてあげることができたら日本語も対応できそうなことが分かる。
どうやって、Cheetahにencoding情報を教えてあげればいいんだろう?
とりあえず/usr/lib/python2.7/dist-packages/Cheetah/Compiler.pyを開いてみる
1558 if source == "":
1559 warnings.warn("You supplied an empty string for the source!", )
1560
1561 else:
1562 unicodeMatch = unicodeDirectiveRE.search(source)
1563 encodingMatch = encodingDirectiveRE.search(source)
1564 if unicodeMatch:
1565 if encodingMatch:
1566 raise ParseError(
1567 self, "#encoding and #unicode are mutually exclusive! "
1568 "Use one or the other.")
1569 source = unicodeDirectiveRE.sub('', source)
1570 if isinstance(source, str):
1571 encoding = unicodeMatch.group(1) or 'ascii'
1572 source = unicode(source, encoding)
1573 elif encodingMatch:
1574 encodings = encodingMatch.groups()
1575 if len(encodings):
1576 encoding = encodings[0]
1577 source = source.decode(encoding)
1578 else:
1579 source = unicode(source)
1563行目のencodingMatchでencodeを調べているっぽい(引数のsourceはpreseed/kickstartファイルに書かれていた文字列が入っている変数)、何をやってるんだろう。見てみる。
どこで定義されているのか?
27 from Cheetah.Parser import Parser, ParseError, specialVarRE, \
28 STATIC_CACHE, REFRESH_CACHE, SET_LOCAL, SET_GLOBAL, SET_MODULE, \
29 unicodeDirectiveRE, encodingDirectiveRE, escapedNewlineRE
あった、あった。Cheetah.Parserというところに、定義があるらしい。見てみる
139 specialVarRE=re.compile(r'([a-zA-z_]+)@') # for matching specialVar comments
140 # e.g. ##author@ Tavis Rudd
141
142 unicodeDirectiveRE = re.compile(
143 r'(?:^|\r\n|\r|\n)\s*#\s{0,5}unicode[:\s]*([-\w.]*)\s*(?:\r\n|\r|\n)', re.MULTILINE)
144 encodingDirectiveRE = re.compile(
145 r'(?:^|\r\n|\r|\n)\s*#\s{0,5}encoding[:\s]*([-\w.]*)\s*(?:\r\n|\r|\n)', re.MULTILINE)
なるほど、Cheetahではファイルの先頭に、encoding情報が書かれていた場合、正規表現でそれを抜き出して、その情報でdecodeするらしい。
正規表現を読み解いてみると、kickstart/preseedファイルの先頭に「#encoding: utf-8 ¥n」を書けばいけることが分かった
# encoding: utf-8
#テストコメント <= (注意)コメントが日本語
#サンプルなので、とりあえずこれだけ
d-i debian-installer/locale string en_US
d-i console-setup/ask_detect boolean false
d-i keyboard-configuration/layoutcode string us
d-i keyboard-configuration/variantcode string
結論
kickstart/preseedファイルに日本語を混ぜる場合は、ファイルの先頭に下記の行を記入する
# encoding: utf-8
# 下記省略
#
ファイル先頭にencoding情報を書いておくことで、テンプレートエンジンのCheetahがきちんとdecodeできるようになり、cobblerでうまくハンドリングできるようになる!
所感
Cheetahを使ったことがなかったので、ソースを読まないと解決できなかったけど。
これぐらい、cobblerでkickstart/preseedファイルを登録する段階で、encodingが指定されていない警告(できれば指定方法も)ぐらい出してくれればいいのになぁ・・・・