一昨日つくった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で始めるネットワーク自動化