さてと、一旦自分のブログに書いたんですが、間違って記事どころかサイトデータ自体を rm -rf しちゃって絶望感がマックスむら…いや何でもないです。はい、書き直します。
えーと、何書いたっけかな…そうそう、鰻だ鰻。神様が「アドカレの 12/1 は鰻ネタを書いて布教せよ」って言うもんだから、鰻ネタ満載な記事にしてやろうと思ったんですよ。
でもね、ほら、僕 Ansible 界の人達とほとんど接点ないもんですから、うかつなことしてアドカレ出禁とかくらったらさすがにショックじゃないすか。なので大人しく鰻ネタじゃなく Ansible ネタを頑張って書いたんですよ。
まぁ、頑張って書いたところで結果は失敗ネタだったので、まぁ、いいんですけどね、いいんですが、同じ記事を2回も書くのは精神が削られるわけですよ。なので本当は「くすっ」っと笑ってもらえるような導入を書いたんですけどね、えぇ、はい、えぇ、消しちゃいましたよ、綺麗さっぱり。俺の鰻を。
で、どんな Ansible ネタを書いたかというと、まぁツマラナイもんですよ。「Ansible で物理スイッチや物理ストレージが設定/操作できるんだからプリンタもやれるべき」とか何とかそんな感じのことを。いやね、僕もできれば「第八宇宙から転生してきたチョネッパリイェルニャンダーがこの次元における歪みから第八宇宙に対して発せられているメロカンバーダシオン光線を止めるために強羅七億土天輝如来菩薩の協力のもと Ansible を使って七転八倒する」みたいな、面白すぎて少年少女の瞳孔がフルオープンするような記事を書きたかったんですよ。書きたかったんですが、ちょっとね、12/1 のエントリーから敷居をあげすぎると、 OpenStack Advent Calendar 2016 のときみたいに「次の日のエントリー、あれ僕だったんですが、すごくやり辛かったです」とか「余計に敷居があがった」とか「難易度高くするのやめて」とか「調子のりすぎ」「やりすぎ」「うなぎ」とか、褒めてんだか賞賛されてんだかよくわからないメッセージを貰うことになるので、自重しました。自重しすぎた結果、記事自体を rm で消しちゃうんですけどね。もうね、どんだけ自重しちゃってんの?って話。自重界のプリンスですよ、もうね。
さて、導入部がグダグダになったところで、Ansible のドキュメントにある Developing Modules に従ってモジュールを書いてみました。
ドキュメントには「Should You Develop A Module?」なんて書いてありますが、僕は英語ができないので、全力スルーですよ。そんなこと言われたら「うん、確かに command モジュールで十分じゃん!」って思うのが人として当然なことなんですが、まぁ、ほら、前述したように、俺鰻ですからね。
で、書いたモジュールは以下です。これを ansible/lib/ansible/modules/printer/epson/epson_ep_804a.py って感じで配置しました。
#!/usr/bin/python
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = '''
---
module: epson_ep_804a
short_description: This is printing module for EPSON EP-804A
version_added: "2.4"
description:
- "This is printing module for EPSON EP-804A."
options:
printer_name:
description:
- Prints files to the named printer.
required: false
copies:
description:
- Sets the number of copies to print.
required: false
files:
description:
- File name.
required: true
media_type:
description:
- "[Print Settings] Media Type"
required: false
print_quality:
description:
- "[Print Settings] Print Quality"
required: false
page_size:
description:
- "[Print Settings] Paper Size"
required: false
input_slot:
description:
- "[Print Settings] Paper Source"
required: false
color:
description:
- "[Print Settings] Color"
required: false
borderless:
description:
- "[Print Settings] Borderless"
required: false
output_paper:
description:
- "[Reduce/Enlarge Document] Output Paper"
required: false
reduce_enlarge:
description:
- "[Reduce/Enlarge Document] Reduce/Enlarge"
required: false
scale_ratio:
description:
- "[Reduce/Enlarge Document] Custom"
required: false
duplex:
description:
- "[Auto Duplex Printing] Duplex Printing - Binding Edge"
required: false
adjust_print_density:
description:
- "[Auto Duplex Printing] Adjust Print Density"
required: false
poster_printing:
description:
- "[Multi-Page] Poster"
required: false
rotate180:
description:
- "[Orientation] Rotate by 180 degrees"
required: false
mirror_image:
description:
- "[Orientation] Mirror Image"
required: false
cd_dvd_inner_print_position:
description:
- "[CD/DVD] CD/DVD Inner Print Position"
required: false
cd_dvd_print_pos_up_down:
description:
- "[CD/DVD] CD/DVD Print Pos. Up-Down"
required: false
cd_dvd_print_pos_left_right:
description:
- "[CD/DVD] CD/DVD Print Pos. Left-Right"
required: false
watermark:
description:
- "[Stampmark] Stampmark"
required: false
colur_watermark:
description:
- "[Stampmark] Color"
required: false
position_watermark:
description:
- "[Stampmark] Position"
required: false
density_watermark:
description:
- "[Stampmark] Density"
required: false
size_watermark:
description:
- "[Stampmark] Size"
required: false
correction_color:
description:
- "[Color Correction] Color Correction"
required: false
gamma_value:
description:
- "[Color Correction] Gamma"
required: false
brightness_value:
description:
- "[Color Correction] Brightness"
required: false
contrast_value:
description:
- "[Color Correction] Contrast"
required: false
saturation_value:
description:
- "[Color Correction] Saturation"
required: false
cyan_value:
description:
- "[Color Correction] Cyan"
required: false
magenta_value:
description:
- "[Color Correction] Magenta"
required: false
yellow_value:
description:
- "[Color Correction] Yellow"
required: false
extends_documentation_fragment:
- epson
author:
- Osamu Habuka (@habuka036)
'''
EXAMPLES = '''
- name: Print two copies of a document to the default printer
epson_ep_804a:
copies: 2
files: filename.txt
- name: Print a legal document to a printer called "foo":
epson_ep_804a:
printer_name: foo
page_size: Legal
files: filename.txt
'''
RETURN = '''
original_message:
description: The original name param that was passed in
type: str
message:
description: The output message that the sample module generates
'''
import subprocess
from ansible.module_utils.basic import AnsibleModule
def run_module():
module_args = dict(
printer_name=dict(type='str', required=False),
copies=dict(type='int', required=False),
files=dict(type='list', required=True),
media_type=dict(type='str', required=False),
print_quality=dict(type='str', required=False),
page_size=dict(type='str', required=False),
input_slot=dict(type='str', required=False),
color=dict(type='str', required=False),
borderless=dict(type='str', required=False),
output_paper=dict(type='str', required=False),
reduce_enlarge=dict(type='str', required=False),
scale_ratio=dict(type='str', required=False),
duplex=dict(type='str', required=False),
adjust_print_density=dict(type='str', required=False),
poster_printing=dict(type='str', required=False),
rotate180=dict(type='str', required=False),
mirror_image=dict(type='str', required=False),
cd_dvd_inner_print_position=dict(type='str', required=False),
cd_dvd_print_pos_up_down=dict(type='str', required=False),
cd_dvd_print_pos_left_right=dict(type='str', required=False),
watermark=dict(type='str', required=False),
colur_watermark=dict(type='str', required=False),
position_watermark=dict(type='str', required=False),
density_watermark=dict(type='str', required=False),
size_watermark=dict(type='str', required=False),
correction_color=dict(type='str', required=False),
gamma_value=dict(type='str', required=False),
brightness_value=dict(type='str', required=False),
contrast_value=dict(type='str', required=False),
saturation_value=dict(type='str', required=False),
cyan_value=dict(type='str', required=False),
magenta_value=dict(type='str', required=False),
yellow_value=dict(type='str', required=False)
)
result = dict(
cmdline='',
exit_status=0,
stderr='',
stdout=''
)
module = AnsibleModule(
argument_spec=module_args,
supports_check_mode=True
)
lpr_options = ['/usr/bin/lpr']
if module.params['printer_name']:
lpr_options.append("-P %s" % module.params['printer_name'])
if module.params['copies']:
lpr_options.append("-# %d" % module.params['copies'])
if module.params['media_type']:
lpr_options.append("-o MediaType=%s" % module.params['media_type'])
if module.params['print_quality']:
lpr_options.append("-o PrintQuality=%s" % module.params['print_quality'])
if module.params['page_size']:
lpr_options.append("-o PageSize=%s" % module.params['page_size'])
if module.params['input_slot']:
lpr_options.append("-o InputSlot=%s" % module.params['input_slot'])
if module.params['color']:
lpr_options.append("-o Color=%s" % module.params['color'])
if module.params['borderless']:
lpr_options.append("-o Borderless=%s" % module.params['borderless'])
if module.params['output_paper']:
lpr_options.append("-o OutputPaper=%s" % module.params['output_paper'])
if module.params['reduce_enlarge']:
lpr_options.append("-o ReduceEnlarge=%s" % module.params['reduce_enlarge'])
if module.params['scale_ratio']:
lpr_options.append("-o ScaleRatio=%s" % module.params['scale_ratio'])
if module.params['duplex']:
lpr_options.append("-o Duplex=%s" % module.params['duplex'])
if module.params['adjust_print_density']:
lpr_options.append("-o AdjustPrintDensity=%s" % module.params['adjust_print_density'])
if module.params['poster_printing']:
lpr_options.append("-o PosterPrinting=%s" % module.params['poster_printing'])
if module.params['rotate180']:
lpr_options.append("-o Rotate180=%s" % module.params['rotate180'])
if module.params['mirror_image']:
lpr_options.append("-o MirrorImage=%s" % module.params['mirror_image'])
if module.params['cd_dvd_inner_print_position']:
lpr_options.append("-o CDDVDInnerPrintPosition=%s" % module.params['cd_dvd_inner_print_position'])
if module.params['cd_dvd_print_pos_up_down']:
lpr_options.append("-o CDDVDPrintPosUpDown=%s" % module.params['cd_dvd_print_pos_up_down'])
if module.params['cd_dvd_print_pos_left_right']:
lpr_options.append("-o CDDVDPrintPosLeftRight=%s" % module.params['cd_dvd_print_pos_left_right'])
if module.params['watermark']:
lpr_options.append("-o Watermark=%s" % module.params['watermark'])
if module.params['colur_watermark']:
lpr_options.append("-o ColurWatermark=%s" % module.params['colur_watermark'])
if module.params['position_watermark']:
lpr_options.append("-o PositionWatermark=%s" % module.params['position_watermark'])
if module.params['density_watermark']:
lpr_options.append("-o DensityWatermark=%s" % module.params['density_watermark'])
if module.params['size_watermark']:
lpr_options.append("-o SizeWatermark=%s" % module.params['size_watermark'])
if module.params['correction_color']:
lpr_options.append("-o CorrectionColor=%s" % module.params['correction_color'])
if module.params['gamma_value']:
lpr_options.append("-o GammaValue=%s" % module.params['gamma_value'])
if module.params['brightness_value']:
lpr_options.append("-o BrightnessValue=%s" % module.params['brightness_value'])
if module.params['contrast_value']:
lpr_options.append("-o ContrastValue=%s" % module.params['contrast_value'])
if module.params['saturation_value']:
lpr_options.append("-o SaturationValue=%s" % module.params['saturation_value'])
if module.params['cyan_value']:
lpr_options.append("-o CyanValue=%s" % module.params['cyan_value'])
if module.params['magenta_value']:
lpr_options.append("-o MagentaValue=%s" % module.params['magenta_value'])
if module.params['yellow_value']:
lpr_options.append("-o YellowValue=%s" % module.params['yellow_value'])
if module.params['files']:
for f in module.params['files']:
lpr_options.append(f)
result['cmdline'] = " ".join(lpr_options)
if module.check_mode:
return result
p = subprocess.Popen(lpr_options, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
r = p.communicate()
result['stdout'] = r[0]
result['stderr'] = r[1]
module.exit_json(**result)
def main():
run_module()
if __name__ == '__main__':
main()
いやー、消えたのがこっちのコードじゃなくてまだ良かった。Python書けないくせに頑張ってPythonらしからぬコードを書いたのに、これが消えたらもう今頃は鰻の歌を歌って YouTube にアップロードして YouTuber デビューをかましてましたからね。
で、次に以下の yaml を書きましたよ。これは unagy.yaml として。
- name: print unagy logo
connection: local
hosts: localhost
tasks:
- name: printing
epson_ep_804a:
files: "{{ item }}"
copies: 1
with_items:
- /home/osamu/鰻/unagi-logo.png
で、以下のように実行したんですよ。
$ ansible-playbook ./unagy.yaml
[WARNING]: Unable to parse /etc/ansible/hosts as an inventory source
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: Could not match supplied host pattern, ignoring: all
[WARNING]: provided hosts list is empty, only localhost is available
ERROR! no action detected in task. This often indicates a misspelled module name, or incorrect module path.
The error appears to have been in '/github.com/ansible/ansible/lib/ansible/modules/printer/epson/unagy.yaml': line 5, column 7, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
tasks:
- name: printing
^ here
The error appears to have been in '/github.com/ansible/ansible/lib/ansible/modules/printer/epson/unagy.yaml': line 5, column 7, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
tasks:
- name: printing
^ here
まぁ、あれですよ、元の記事だと「あるぇ〜?」「なんでぇ〜?」とか焦った様子を書いたんですが、もうね、消えちゃったあとだとこんなエラーごときじゃ焦らないわけですよ。もうね心はまるで南極の氷の下の100万年前の海ぐらい穏やかですよ。
まぁ、結局初日から失敗ネタで大変申し訳ないと思います。もうこんなに心踊らない記事を書いてる自分が腑甲斐ないやら何やらで、もう「なゆかどっかに失踪したい」と思ってしまうぐらい。( @ishikawa84g さん、「なゆか」ネタはもうこれで勘弁してください ><)
Ansible ネタなのにこんなしめくくりで申し訳ないんですが「git の管理下にあるものはとりあえず push しろ、ビルドだの何だのはあとでやれ」です。「人は rm を手に入れたときから破滅する未来も一緒に手に入れたのだ」とか「人類に rm -rf は早すぎた」とか、他にも色々と言えるんですが、蛇足なので割愛します。
さて、気を取り直して、明日の Ansible Advent Calendar 2017 の二日目のエントリーは、日本鰻師同好会の名誉会員である @tsukaman さんの記事です。お楽しみに〜。