Contents
以前、moleculeのVMwareドライバを使ったAnsibleロールのテスト方法についてblogを書きました。
ただし、上記の記事はVMwareドライバのPRがWIPになっており、マージされていません。
そこで、ここでは delegated
ドライバを使った方法を試してみます。
delegated
ドライバを使う目的の一つとして、ドライバが存在していないがテスト用インタンスを、その環境に作りたい場合などが考えられます。
delegated
ドライバを使うにはテスト用インスタンスを用意するPlaybookなどを書かなくてはいけないので大変ですが、やり方さえ分かってしまえば色々と自由度が広がると思います。
環境
項目 | バージョン | 備考 |
---|---|---|
vCenter | 6.7.0 | |
molecule | 2.22 | |
OS | CentOS 7.6 | moleculeを実行するOS |
Template OS | CentOS 7.6 | ロールのテストで使うテンプレート |
delegatedドライバを使うために必要なファイル
以下のファイルをユーザーで用意する必要があります。
ファイル | 必要 | 説明 |
---|---|---|
create.yml | True | テスト用インスタンスを用意するためのPlaybook |
prepare.yml | False | テストを実行する前に実行するタスクを記述するPlaybook |
destroy.yml | True | テスト用インスタンスを削除するためのPlaybook |
今回作った階層
今回は以下の hello
ロールを作りました。
あくまでも動作を確認するテスト用なので、ただメッセージを表示するだけのロールです。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
(venv) [root@localhost roles]# tree hello/ hello/ ├── molecule │ └── default │ ├── create.yml │ ├── destroy.yml │ ├── molecule.yml │ ├── playbook.yml │ ├── prepare.yml │ └── yamllint.yml └── tasks └── main.yml |
順番にファイルを見ていきます。
ファイル
create.yml
以下のPlaybookはVMware環境にテスト用のインスタンスを作成するものです。
テンプレートからVMをクローンしてSSHの鍵を埋め込みmoleculeが接続できるようの設定を作っています。
create.yml
では インスタンスの作成
と インスタンスへの接続用の設定ファイル作成
をすればいいです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
--- - name: Create hosts: localhost connection: local gather_facts: false no_log: "{{ not (lookup('env', 'MOLECULE_DEBUG') | bool or molecule_yml.provisioner.log | default(false) | bool) }}" vars: keypair_path: "{{ lookup('env','MOLECULE_EPHEMERAL_DIRECTORY') }}/ssh_key" tasks: - name: Create keypair. user: name: "{{ lookup('env','USER') }}" generate_ssh_key: true ssh_key_file: "{{ keypair_path }}" register: keypair_result - name: Create molecule instance(s). vmware_guest: hostname: "{{ molecule_yml.driver.hostname }}" username: "{{ molecule_yml.driver.username }}" password: "{{ molecule_yml.driver.password }}" validate_certs: "{{ molecule_yml.driver.validate_certs | default(false) }}" datacenter: "{{ molecule_yml.driver.datacenter }}" esxi_hostname: "{{ molecule_yml.driver.esxi_hostname }}" folder: "{{ molecule_yml.driver.folder }}" name: "{{ item.name }}" template: "{{ item.template }}" hardware: memory_mb: "{{ item.memory_mb }}" num_cpus: "{{ item.cpus }}" networks: - name: "{{ item.network }}" datastore: "{{ item.datastore }}" wait_for_ip_address: "yes" state: poweredon register: server with_items: "{{ molecule_yml.platforms }}" - name: Create ssh directory and public key in guest vm. vmware_vm_shell: hostname: "{{ molecule_yml.driver.hostname }}" username: "{{ molecule_yml.driver.username }}" password: "{{ molecule_yml.driver.password }}" validate_certs: "{{ molecule_yml.driver.validate_certs | default(false) }}" datacenter: "{{ molecule_yml.driver.datacenter }}" folder: "{{ molecule_yml.driver.folder }}" vm_id: "{{ item.name }}" vm_username: "{{ molecule_yml.driver.vm_username }}" vm_password: "{{ molecule_yml.driver.vm_password }}" vm_shell: /bin/bash vm_shell_args: "-c 'mkdir -p ~/.ssh && chmod 700 ~/.ssh && echo {{ keypair_result.ssh_public_key }} > ~/.ssh/authorized_keys'" wait_for_process: true with_items: "{{ molecule_yml.platforms }}" - name: Populate instance config dict. set_fact: instance_conf_dict: { 'instance': "{{ item.instance.hw_name }}", 'address': "{{ item.instance.ipv4 }}", 'user': "{{ molecule_yml.driver.vm_username }}", 'port': 22, 'identity_file': "{{ keypair_path }}" } with_items: "{{ server.results }}" register: instance_config_dict when: server is changed - name: Convert instance config dict to a list. set_fact: instance_conf: "{{ instance_config_dict.results | map(attribute='ansible_facts.instance_conf_dict') | list }}" when: server is changed - name: Dump instance config. copy: # NOTE(retr0h): Workaround for Ansible 2.2. # https://github.com/ansible/ansible/issues/20885 content: "{{ instance_conf | to_json | from_json | molecule_to_yaml | molecule_header }}" dest: "{{ molecule_instance_config }}" when: server is changed |
destroy.yml
以下のPlaybookはVMware環境に作成したインスタンスを削除するものです。
destroy.yml
では インスタンスの削除
をすればいいです。
ただし molecule test
の初回でも実行されるので、存在しない場合はエラーにならないようにする必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
--- - name: Destroy hosts: localhost connection: local gather_facts: false no_log: "{{ not (lookup('env', 'MOLECULE_DEBUG') | bool or molecule_yml.provisioner.log | default(false) | bool) }}" tasks: - name: Gather fact from molecule instance(s). vmware_guest_facts: hostname: "{{ molecule_yml.driver.hostname }}" username: "{{ molecule_yml.driver.username }}" password: "{{ molecule_yml.driver.password }}" validate_certs: "{{ molecule_yml.driver.validate_certs }}" datacenter: "{{ molecule_yml.driver.datacenter }}" folder: "{{ molecule_yml.driver.folder }}" name: "{{ item.name }}" register: server_fact_result loop: "{{ molecule_yml.platforms }}" loop_control: label: "{{ item.name }}" ignore_errors: true - name: Poweredoff molecule instance(s). vmware_guest: hostname: "{{ molecule_yml.driver.hostname }}" username: "{{ molecule_yml.driver.username }}" password: "{{ molecule_yml.driver.password }}" validate_certs: "{{ molecule_yml.driver.validate_certs }}" datacenter: "{{ molecule_yml.driver.datacenter }}" esxi_hostname: "{{ molecule_yml.driver.esxi_hostname }}" folder: "{{ molecule_yml.driver.folder }}" name: "{{ item.instance.hw_name }}" state: poweredoff loop: "{{ server_fact_result.results }}" loop_control: label: "{{ item.instance.hw_name | default('not find vm') }}" when: - "'instance' in item" - item.instance.hw_power_status != "poweredOff" - name: Destroy molecule instance(s). vmware_guest: hostname: "{{ molecule_yml.driver.hostname }}" username: "{{ molecule_yml.driver.username }}" password: "{{ molecule_yml.driver.password }}" validate_certs: "{{ molecule_yml.driver.validate_certs }}" datacenter: "{{ molecule_yml.driver.datacenter }}" esxi_hostname: "{{ molecule_yml.driver.esxi_hostname }}" folder: "{{ molecule_yml.driver.folder }}" name: "{{ item.instance.hw_name }}" state: absent loop: "{{ server_fact_result.results }}" loop_control: label: "{{ item.instance.hw_name | default('not find vm') }}" when: - "'instance' in item" |
prepare.yml
これは任意のファイルです。
テスト用のインスタンスでロールを実行する前にやっておくタスクを記述します。
ここでは、動作を確認するために以下のPlaybookを作成しました。
1 2 3 4 5 6 7 8 9 10 |
--- - name: Prepare hosts: all gather_facts: no tasks: - name: crete file. copy: dest: ~/hello.txt content: "Hello, World!!" |
molecule.yml
molecule.yml
は以下のようにしました。
driver
や platforms
は自作した create.yml
destroy.yml
から呼べるようにキーを追加しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
--- dependency: name: galaxy driver: name: delegated hostname: vCenter ip username: administrator@vsphere.local password: password validate_certs: false datacenter: DC esxi_hostname: esxi name folder: /vm/CI vm_username: root vm_password: password options: ansible_connection_options: connection: ssh lint: name: yamllint options: config-file: molecule/default/yamllint.yml platforms: - name: instance template: CentOS7_TMP memory_mb: 2048 cpus: 2 network: VM Network datastore: VM2 provisioner: name: ansible lint: name: ansible-lint options: x: - 502 log: true verifier: name: testinfra lint: name: flake8 |
その他のmolecule設定については詳しく説明しませんので、以下のドキュメントを参照ください。
playbook.yml
テストするPlaybookは標準で作成されたものをそのまま使います。
1 2 3 4 5 6 |
--- - name: Converge hosts: all roles: - role: hello |
yamllint.yml
以下は、yamllintの対象外ファイルリストを作りました。
1 2 3 4 5 6 7 |
--- extends: default ignore: | create.yml destroy.yml prepare.yml |
デモ
以下がデモ動画です。
Demo to create test instance in VMware using delegated driver from sky_joker on Vimeo.
最後に
delegated
ドライバを使うことでVMware環境にもテスト用インスタンスが作成できることが確認できました 🙂
標準ドライバで大体のことは出来てしまうと思いますが、例外の場合はdelegatedドライバで自由に環境が作れますね。
moleculeを使ってテストも自動化してみんなでハッピーオートメーション!