質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

Vagrant

Vagrantは、VirtualBox上の仮想マシンを コマンドラインから作成してくれるソフトウェアです。 ビルド環境など容易に構築が可能です。

Ansible

Ansibleは、Python で書かれたサーバーの設定を管理するための 構成管理ツールです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

872閲覧

Dynamic Inventoryが正常に動かない。

Yuta_for

総合スコア21

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

Vagrant

Vagrantは、VirtualBox上の仮想マシンを コマンドラインから作成してくれるソフトウェアです。 ビルド環境など容易に構築が可能です。

Ansible

Ansibleは、Python で書かれたサーバーの設定を管理するための 構成管理ツールです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/04/18 07:19

編集2020/04/25 04:40

エラー概要

Pythonで記載されたスクリプトが起動しない。

##エラーの詳細
Ansibleの勉強のために以下の技術書に記載されているDynamic Inventoryスクリプトを起動しましたが型エラーでつまずいてしまいました。

Python

1#!/usr/bin/env python 2""" 3Vagrant external inventory script. Automatically finds the IP of the booted vagrant vm(s), and 4returns it under the host group 'vagrant' 5Example Vagrant configuration using this script: 6 config.vm.provision :ansible do |ansible| 7 ansible.playbook = "./provision/your_playbook.yml" 8 ansible.inventory_file = "./provision/inventory/vagrant.py" 9 ansible.verbose = true 10 end 11""" 12 13import sys 14import os.path 15import subprocess 16import re 17from paramiko import SSHConfig 18from io import StringIO 19from optparse import OptionParser 20from collections import defaultdict 21try: 22 import json 23except: 24 import simplejson as json 25 26_group = 'vagrant' # a default group 27_ssh_to_ansible = [('user', 'ansible_ssh_user'), 28 ('hostname', 'ansible_ssh_host'), 29 ('identityfile', 'ansible_ssh_private_key_file'), 30 ('port', 'ansible_ssh_port')] 31 32# Options 33# ------------------------------ 34 35parser = OptionParser(usage="%prog [options] --list | --host <machine>") 36parser.add_option('--list', default=False, dest="list", action="store_true", 37 help="Produce a JSON consumable grouping of Vagrant servers for Ansible") 38parser.add_option('--host', default=None, dest="host", 39 help="Generate additional host specific details for given host for Ansible") 40(options, args) = parser.parse_args() 41 42# 43# helper functions 44# 45 46 47# get all the ssh configs for all boxes in an array of dictionaries. 48def get_ssh_config(): 49 return dict((k, get_a_ssh_config(k)) for k in list_running_boxes()) 50 51 52# list all the running boxes 53def list_running_boxes(): 54 output = subprocess.check_output(["vagrant", "status"]).split('\n') 55 56 boxes = [] 57 58 for line in output: 59 matcher = re.search("([^\s]+)[\s]+running (.+", line) 60 if matcher: 61 boxes.append(matcher.group(1)) 62 63 return boxes 64 65 66# get the ssh config for a single box 67def get_a_ssh_config(box_name): 68 """Gives back a map of all the machine's ssh configurations""" 69 70 output = subprocess.check_output(["vagrant", "ssh-config", box_name]) 71 config = SSHConfig() 72 config.parse(StringIO(output)) 73 host_config = config.lookup(box_name) 74 75 # man 5 ssh_config: 76 # > It is possible to have multiple identity files ... 77 # > all these identities will be tried in sequence. 78 for id in host_config['identityfile']: 79 if os.path.isfile(id): 80 host_config['identityfile'] = id 81 82 return dict((v, host_config[k]) for k, v in _ssh_to_ansible) 83 84# List out servers that vagrant has running 85# ------------------------------ 86if options.list: 87 ssh_config = get_ssh_config() 88 meta = defaultdict(dict) 89 90 for host in ssh_config: 91 meta['hostvars'][host] = ssh_config[host] 92 93 print((json.dumps({_group: list(ssh_config.keys()), '_meta': meta}))) 94 sys.exit(0) 95 96# Get out the host details 97# ------------------------------ 98elif options.host: 99 print((json.dumps(get_a_ssh_config(options.host)))) 100 sys.exit(0) 101 102# Print out help 103# ------------------------------ 104else: 105 parser.print_help() 106 sys.exit(0) 107 108実行結果 109yuta@yuta-PC:~/Desktop/work/ansible/ansible-tutorial$ ./vagrant.py --list 110Traceback (most recent call last): 111 File "./vagrant.py", line 108, in <module> 112 ssh_config = get_ssh_config() 113 File "./vagrant.py", line 70, in get_ssh_config 114 return dict((k, get_a_ssh_config(k)) for k in list_running_boxes()) 115 File "./vagrant.py", line 75, in list_running_boxes 116 output = subprocess.check_output(["vagrant", "status"]).split('\n') 117TypeError: a bytes-like object is required, not 'str'

書籍の想定出力ですと以下のようになるみたいです。

Python

1{ 2 "vagrant": [ 3 "default" 4 ], 5 "_meta": { 6 "hostvars": { 7 "default": { 8 "ansible_ssh_host": "127.0.0.1", 9 "ansible_ssh_port": "2222", 10 "ansible_ssh_user": "vagrant", 11 "ansible_ssh_private_key_file": "Users/username/ansible-tutorial/.vagrant/machines/default/virtualbox/private_key" 12 } 13 } 14 } 15}

もともとPython2系で書かれていたみたいで、2to3ツールで3に変換した上で実行したのですが、エラーが発生しました。
以前も同じようなエラーが出た時に質問したのですが、
TypeError: a bytes-like object is required, not 'str' 左記のエラーから文字コードを指定してバイト型に変換する必要があるとのことで、
output = subprocess.check_output([b"vagrant", b"status"]).split('\n')
上記のようにバイト変換をしましたが、結果は変わりませんでした。
前提条件となるVagrantの起動は完了しております。
他にどうすればよいのか分からなくてわかる人がいましたらご教授お願いいたします。

追記
レシーバにdecode()を修正して実行しましたが、別エラーが発生しました。

Python

1# list all the running boxes 2def list_running_boxes(): 3 output = subprocess.check_output(["vagrant", "status"]).decode().split('\n') 4 5 boxes = [] 6 7 for line in output: 8 matcher = re.search("([^\s]+)[\s]+running (.+", line) 9 if matcher: 10 boxes.append(matcher.group(1)) 11 12 return boxes 13 14実行結果 15yuta@yuta-PC:~/Desktop/work/ansible/ansible-tutorial$ ./vagrant.py --list 16Traceback (most recent call last): 17 File "./vagrant.py", line 108, in <module> 18 ssh_config = get_ssh_config() 19 File "./vagrant.py", line 70, in get_ssh_config 20 return dict((k, get_a_ssh_config(k)) for k in list_running_boxes()) 21 File "./vagrant.py", line 70, in <genexpr> 22 return dict((k, get_a_ssh_config(k)) for k in list_running_boxes()) 23 File "./vagrant.py", line 93, in get_a_ssh_config 24 config.parse(StringIO(output)) 25TypeError: initial_value must be str or None, not bytes

2020/4/25(土)追記
頂いた回答を基に修正したコードです。

Python

1 2#!/usr/bin/env python 3 4import sys 5import os.path 6import subprocess 7import re 8from paramiko import SSHConfig 9from io import BytesIO 10from optparse import OptionParser 11from collections import defaultdict 12try: 13 import json 14except: 15 import simplejson as json 16 17_group = 'vagrant' # a default group 18_ssh_to_ansible = [('user', 'ansible_ssh_user'), 19 ('hostname', 'ansible_ssh_host'), 20 ('identityfile', 'ansible_ssh_private_key_file'), 21 ('port', 'ansible_ssh_port')] 22 23# Options 24# ------------------------------ 25 26parser = OptionParser(usage="%prog [options] --list | --host <machine>") 27parser.add_option('--list', default=False, dest="list", action="store_true", 28 help="Produce a JSON consumable grouping of Vagrant servers for Ansible") 29parser.add_option('--host', default=None, dest="host", 30 help="Generate additional host specific details for given host for Ansible") 31(options, args) = parser.parse_args() 32 33# 34# helper functions 35# 36 37 38# get all the ssh configs for all boxes in an array of dictionaries. 39def get_ssh_config(): 40 return dict((k, get_a_ssh_config(k)) for k in list_running_boxes()) 41 42 43# list all the running boxes 44def list_running_boxes(): 45 output = subprocess.check_output([b"vagrant", b"status"]).split(b'\n') #bを追加してbyte変換 46 47 boxes = [] 48 49 for line in output: 50 matcher = re.search(b"([^\s]+)[\s]+running (.+", line) #bを追加してbyte変換 51 if matcher: 52 boxes.append(matcher.group(1)) 53 54 return boxes 55 56 57# get the ssh config for a single box 58def get_a_ssh_config(box_name): 59 """Gives back a map of all the machine's ssh configurations""" 60 61 output = subprocess.check_output(["vagrant", "ssh-config", box_name]) 62 config = SSHConfig() 63 config.parse(BytesIO(output)) 64 host_config = config.lookup(box_name) 65 66 # man 5 ssh_config: 67 # > It is possible to have multiple identity files ... 68 # > all these identities will be tried in sequence. 69 for id in host_config['identityfile']: 70 if os.path.isfile(id): 71 host_config['identityfile'] = id 72 73 return dict((v, host_config[k]) for k, v in _ssh_to_ansible) 74 75# List out servers that vagrant has running 76# ------------------------------ 77if options.list: 78 ssh_config = get_ssh_config() 79 meta = defaultdict(dict) 80 81 for host in ssh_config: 82 meta['hostvars'][host] = ssh_config[host] 83 84 print((json.dumps({_group: list(ssh_config.keys()), '_meta': meta}))) 85 sys.exit(0) 86 87# Get out the host details 88# ------------------------------ 89elif options.host: 90 print((json.dumps(get_a_ssh_config(options.host)))) 91 sys.exit(0) 92 93# Print out help 94# ------------------------------ 95else: 96 parser.print_help() 97 sys.exit(0) 98 99実行 100python vagrant.py --list 101Traceback (most recent call last): 102 File "vagrant.py", line 108, in <module> 103 ssh_config = get_ssh_config() 104 File "vagrant.py", line 70, in get_ssh_config 105 return dict((k, get_a_ssh_config(k)) for k in list_running_boxes()) 106 File "vagrant.py", line 70, in <genexpr> 107 return dict((k, get_a_ssh_config(k)) for k in list_running_boxes()) 108 File "vagrant.py", line 93, in get_a_ssh_config 109 config.parse(BytesIO(output)) 110 File "/home/yuta/.pyenv/versions/3.8.2/lib/python3.8/site-packages/paramiko/config.py", line 136, in parse 111 if not line or line.startswith("#"): 112TypeError: startswith first arg must be bytes or a tuple of bytes, not str 113 114

エラーの内容から最初の引数をバイトにしないといけないと出力されていますが、エラー先がpyenv以下のparamikoパッケージのコンフィグファイルであり、この部分を修正するということでしょうか?
pip でインストールしたモジュールのコンフィグファイルを変更することに少し不安感を覚えるのですがこの考えは間違っていないのかご教授お願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

output = subprocess.check_output([b"vagrant", b"status"]).split('\n')

上記のようにバイト変換をしましたが、結果は変わりませんでした。

コマンドは割とどうでもよくて、splitの方でエラーになっています。subprocess.check_output自体はbytesを返します。bytes.splitだからb'\n'で分割しないといけないのです。

投稿2020/04/20 14:12

hayataka2049

総合スコア30933

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Yuta_for

2020/04/25 04:42

回答ありがとうございます。 指摘された回答を基に修正したところ新たなエラーがでてしまい自分の考えで間違っていないかお手すきの際にご確認してもよろしいでしょうか?
hayataka2049

2020/04/25 09:32

strで渡せばいいのでは?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問