一昨日つくったcEOS-labコンテナにAnsibleのeosモジュール使ってアクセスする。
使うモジュールはひとまず情報収集のeos_factsを使用。
ネットワーク初心者の自分にはハマりポイントが大量にあったので色々と備忘録。
ポイントは「相手がコンテナであることは忘れろ。Linuxでも無い」だった笑
答え
コンテナ内22/TCPのpublish設定
(未確認だけど原理的に)無くても(コンテナのIPアドレスチェックして直接接続にいけば多分)動くっちゃ動く(と思う)けど分かりやすいように。
$ docker create --name=ceos-4-21 --privileged -p 25022:22 -e CEOS=1 -e container=docker -e EOS_PLATFORM=ceoslab -e SKIP_ZEROTOUCH_BARRIER_IN_SYSDBINIT=1 -e ETBA=1 -e INTFTYPE=eth -i -t ceos:4.21.12M /sbin/init
こんな感じでコンテナを作り直す。(25022
は適当)
要はcEOS-Labコンテナ内ではsshdが動いてるので、それを外からアクセスできるようにする。
[zaki@cloud-dev dev]$ docker exec -it ceos-4-21 bash bash-4.3# lsof -i:22 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME xinetd 1412 root 5u IPv4 3691233 0t0 TCP *:ssh (LISTEN) xinetd 1412 root 6u IPv6 3691234 0t0 TCP *:ssh (LISTEN) sshd 2981 root 3u IPv4 3729852 0t0 TCP 172.17.0.2:ssh->172.17.0.1:directplaysrvr (ESTABLISHED) sshd 2981 root 4u IPv4 3729852 0t0 TCP 172.17.0.2:ssh->172.17.0.1:directplaysrvr (ESTABLISHED) bash-4.3# ss -anptl (省略)
ちなみにcEOS-lab 4.21.12Mの土台はFedora 18だった
bash-4.3# cat /etc/redhat-release Fedora release 18 (Spherical Cow)
cEOS-lab側設定
Cli
でアクセスするユーザー作成&enable
が出来る権限設定を行う。
bash-4.3# Cli localhost>enable localhost#configure localhost(config)#username lab-user privilege 15 secret p@ssword
これで、外部からsshしつつenable
で昇格も可能。
[zaki@cloud-dev ~]$ ssh lab-user@localhost -p 25022 Password: localhost>enable localhost#
paramiko
paramiko
が必要なのでAnsibleコントロールノードにpip
でインストールする。
(別件で入れてたので遭遇しなかったけど、無いと「paramikoがないよ」ってエラーになる)
TASK [gather facts] fatal: [localhost]: FAILED! => changed=false ansible_facts: discovered_interpreter_python: /usr/bin/python msg: 'paramiko is not installed: No module named ''paramiko'''
Ansible
playbook
- hosts: eos gather_facts: no tasks: - name: gather facts eos_facts: gather_subset: all register: eosfacts - debug: msg: "{{eosfacts}}"
inventory
[eos] localhost
group_vars/eos.yml
ansible_connection: network_cli ansible_network_os: eos ansible_port: 25022 ansible_user: lab-user ansible_password: p@ssword ansible_become: yes ansible_become_method: enable
あとは必要に応じてansible.cfg
でstdout_callback = yaml
など。
ファイルは一式GitHubに置いてる。
実行
$ ansible-playbook -i inventory.ini playbook.yml PLAY [eos] ***************************************************************************************************************************************************** TASK [gather facts] ******************************************************************************************************************************************** [WARNING]: default value for `gather_subset` will be changed to `min` from `!config` v2.11 onwards ok: [localhost] TASK [debug] *************************************************************************************************************************************************** ok: [localhost] => msg: ansible_facts: ansible_net_all_ipv4_addresses: [] ansible_net_all_ipv6_addresses: [] ansible_net_api: cliconf ansible_net_config: |- ! Command: show running-config ! device: localhost (cEOSLab, EOS-4.21.12M-18662095.42112M (engineering build)) ! transceiver qsfp default-mode 4x10G ! spanning-tree mode mstp ! no aaa root ! username lab-user privilege 15 secret sha512 <*** hash-value ***> username test01 privilege 10 secret sha512 <*** hash-value ***> username test02 privilege 15 secret sha512 <*** hash-value ***> ! no ip routing ! end ansible_net_filesystems: - 'file:' - 'flash:' - 'system:' ansible_net_fqdn: localhost ansible_net_gather_network_resources: [] ansible_net_gather_subset: - hardware - default - interfaces - config ansible_net_hostname: localhost ansible_net_interfaces: {} ansible_net_memfree_mb: 1179.5234375 ansible_net_memtotal_mb: 7802.80859375 ansible_net_model: cEOSLab ansible_net_neighbors: {} ansible_net_python_version: 2.7.5 ansible_net_serialnum: '' ansible_net_system: eos ansible_net_version: 4.21.12M-18662095.42112M (engineering build) ansible_network_resources: {} discovered_interpreter_python: /usr/bin/python changed: false failed: false warnings: - default value for `gather_subset` will be changed to `min` from `!config` v2.11 onwards PLAY RECAP ***************************************************************************************************************************************************** localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
username
のところは、作成したユーザーがリストされている。
勘違いしてたこと
コンテナなんだからconnection=docker使う?
昨日書いた記事はこれの準備のつもりだったけど、ハズレでした。
ちなみにansible_connection=docker
で接続しようとするとEOSとして扱おうとしてくれず、そもそも組み合わせ不可となる。
TASK [gather facts] fatal: [localhost]: FAILED! => changed=false msg: Connection type docker is not valid for this module
正解は
ansible_connection: network_cli ansible_network_os: eos
参考
そうですそうです!https://t.co/zQ35g7DMEI の「接続できないエラーが発生」の原因と対処が参考になるかと思います。
— よこち(yokochi) (@akira6592) 2020年9月20日
ansible_connection: docker してしまうと、ネットワークOSとしてではなく、Linuxとして操作しようとするので eos モジュールが使えないんですよね。
ssh接続用のユーザーをuseradd
で用意する
デフォルトだと/etc/passwd
を見る限り接続に使えそうなユーザーがいないので、useradd
で接続用ユーザーを作ったのですが、これもハズレ。
bash-4.3# useradd -m ansible bash-4.3# passwd ansible
これで作ったアカウント情報をAnsibleで設定して実行しても
TASK [gather facts] ******************************************************************************************************************************************** fatal: [localhost]: FAILED! => changed=false ansible_facts: discovered_interpreter_python: /usr/bin/python msg: unable to set terminal parameters
って感じ。
これ、-vvv
付けても追加されるスタックトレースは
The full traceback is: WARNING: The below traceback may *not* be related to the actual failure. File "/tmp/ansible_eos_facts_payload_cxWm95/ansible_eos_facts_payload.zip/ansible/module_utils/network/common/network.py", line 229, in get_capabilities capabilities = Connection(module._socket_path).get_capabilities() File "/tmp/ansible_eos_facts_payload_cxWm95/ansible_eos_facts_payload.zip/ansible/module_utils/connection.py", line 185, in __rpc__ raise ConnectionError(to_text(msg, errors='surrogate_then_replace'), code=code) fatal: [localhost]: FAILED! => changed=false
って感じでホントよくわからんかったけど、msg
で出ているログは多分ここ。
def on_open_shell(self): try: for cmd in (b'terminal length 0', b'terminal width 512'): self._exec_cli_command(cmd) except AnsibleConnectionFailure: raise AnsibleConnectionFailure('unable to set terminal parameters')
というのも、useradd
で作ったユーザーでssh
で入ってシェルのhistory(Ctrl-p)を見ると、terminal length 0
を叩いた形跡があり、でもterminal
なんてコマンドは無いのでsshのレイヤーでは接続に成功してるけどAnsibleの実行に失敗してることがわかる。
(ちなみに、コンテナ内の/var/log/messages
を見ても、Ansible実行のタイミングでsshはstatus=0
で終了している)
[zaki@cloud-dev ~]$ ssh ansible@localhost -p 25022 Password: Last login: Mon Sep 21 01:06:11 2020 from 172.17.0.1 Arista Networks EOS shell [ansible@localhost ~]$ [ansible@localhost ~]$ history | grep terminal 1 terminal length 0 3 terminal length 0 9 terminal length 0 10 history | grep terminal [ansible@localhost ~]$ terminal length 0 -bash: terminal: command not found
じゃあこのコマンドってどこで実行するのかっていうと、Cli
のシェル上で実行するのね。
[ansible@localhost ~]$ Cli localhost>terminal length 0 Pagination disabled. localhost>terminal length 512 Pagination set to 512 lines.
つまりAnsibleの実行も、接続したときにCli
が起動してるのを期待してるというわけ。
そこで、最初からCli
が起動してればいいじゃんということで、chsh
でログインシェルを変更してみる。
bash-4.3# chsh ansible Changing shell for ansible. New shell [/bin/bash]: /usr/bin/Cli Shell changed. bash-4.3# chsh ansible Changing shell for ansible.
これで素のsshでもAnsible実行でも、「作成したユーザーでssh接続しつつEOSのシェル(Cli
)でコマンドを打てる」というところまでは動く。
ただし、、、
[zaki@cloud-dev ~]$ ssh ansible@localhost -p 25022 Password: Last login: Mon Sep 21 01:14:24 2020 from 172.17.0.1 localhost>show version cEOSLab Hardware version: Serial number: System MAC address: Not available Software image version: 4.21.12M-18662095.42112M (engineering build) Architecture: i386 Internal build version: 4.21.12M-18662095.42112M Internal build ID: 3266415c-55a9-403c-a020-777efe5ff9aa cEOS tools version: 1.1 Uptime: 0 weeks, 5 days, 11 hours and 51 minutes Total memory: 7990076 kB Free memory: 1296380 kB localhost>enable % Cannot authenticate unknown uid 1000
こんな感じでenable
で特権を得られなかった。
ansible-playbook
でもこんな感じ。
TASK [gather facts] fatal: [localhost]: FAILED! => changed=false ansible_facts: discovered_interpreter_python: /usr/bin/python msg: 'unable to elevate privilege to enable mode, at prompt [b''\nlocalhost>''] with error: failed to elevate privilege to enable mode still at prompt [b''\nlocalhost>'']'
作成したユーザーの昇格設定がわからなかったのと、rootユーザーをchsh
しても回避できそうだけど、さすがにその設定は不都合が多すぎの予感がしたので別の方法が無いかと思った。
参考
正解は、OSのユーザーを作成するのでなく、EOSのユーザー(って言い方でいいのかな?)を作成すればOK。
権限も設定できるし、作成したユーザー名で外部からsshもできる。
ユーザー作成は一旦rootで(docker exec -it
でシェル起動して)Cli
コマンドで、configure
を起動してからusername
コマンドを使用する。
その際、OSユーザーと同名のアカウントは作成できない模様。
localhost#username ansible privilege 15 secret ansible % Invalid input localhost#configure localhost(config)#username ansible privilege 15 secret ansible % Unable to create reserved username 'ansible'. Please try another. localhost(config)#username test01 privilege 10 secret test01 localhost(config)#username test02 privilege 15 secret test02 localhost(config)#username lab-user privilege 15 secret p@ssword
これで、test01
もtest02
もlab-user
もsshで接続すればCli
が起動する。
(これらのユーザーは/etc/passwd
には記載されない)
参考
その他関連情報
- Ansible
- Arista EOS関連
- ARISTA cEOS-lab で NETCONF を動かす (小ネタ) - kakkotetsu はてなブログ
- Arista EOS Central - OpenConfig 4.20.2.1F Release Notes
- ネットワーク上のコンテナネットワーク / janog43-shtsuchi-lxc-00 (スライド)
- 【講演資料_アリスタネットワークス】Arista Networksが実現する Ansibleによるネットワーク自動化とcEOS-labを使ったネットワークシミュレーション (スライド)
- AristaNetworks cEOS-labのインストールと起動(Docker for Windows) - Qiita
- GNS3でArista cEOSを動かす - Qiita
- Arista EOS Central - AnsibleとRead-Onlyで始めるネットワーク自動化