Moleculeで変数、および環境変数を渡す処理について考察してみます。
サンプルコードはこちらになります。
Ansibleの変数とは
Ansibleの変数は主にPlaybookの処理の変更にバリエーションをもたらすために用いられます。例えばホストAでは値Xを適応したいがホストBでは値Yを適応したい場合、などです。
Moleculeで変数を渡す場合
Moleculeが変数を利用するポイントはいくつかあります。
- molecule.yml
- group_vars/all
- varsファイル
molecule.ymlで変数を設定し利用するケース
molecule.ymlは「molecule/scenario-name/molecule.yml」に配置されるMoleculeの動作をシナリオレベルで決める事の出来る設定ファイルです。
---
dependency:
name: galaxy
driver:
name: ec2
platforms:
- name: instance1
image: ami-xxxxxxxxxxxxxx
instance_type: instance.type
vpc_subnet_id: subnet-xxxxxxxxxxxxx
keypair_name: keypair_instance1
security_group_name: sg_instance1
- name: instance2
image: ami-xxxxxxxxxxxxxx
instance_type: instance.type
vpc_subnet_id: subnet-xxxxxxxxxxxxx
keypair_name: keypair_instance1
security_group_name: sg_instance1
provisioner:
name: ansible
connection_options:
var1: vaule1
var2: vaule2
var3: vaule3
log: true
playbooks:
converge: ../../install.yml
verifier:
name: ansible
scenario:
test_sequence:
- dependency
- cleanup
- destroy
- syntax
- create
- converge
- cleanup
- destroy
platformsセクション
platformsセクションで設定した変数はどのシナリオファイルからでも呼び出す事が出来ます。例えばcreate.ymlでAWS EC2へインスタンスを起動したい場合
このplatformsセクションで指定してcreate.yml側で呼び出せます。
クリックで記述を表示する
---
- name: Create
hosts: localhost
connection: local
gather_facts: false
no_log: "{{ molecule_no_log }}"
vars:
ssh_user: centos
ssh_port: 22
security_group_description: Security group for testing Molecule
security_group_rules:
- proto: tcp
from_port: "{{ ssh_port }}"
to_port: "{{ ssh_port }}"
cidr_ip: '0.0.0.0/0'
- proto: icmp
from_port: 8
to_port: -1
cidr_ip: '0.0.0.0/0'
security_group_rules_egress:
- proto: -1
from_port: 0
to_port: 0
cidr_ip: '0.0.0.0/0'
keypair_path: "{{ lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') }}/ssh_key"
tasks:
- name: Create security group
ec2_group:
name: "{{ item.security_group_name }}"
description: "{{ item.security_group_name }}"
rules: "{{ security_group_rules }}"
rules_egress: "{{ security_group_rules_egress }}"
loop: "{{ molecule_yml.platforms }}"
loop_control:
index_var: index
register: security_group
- name: Test for presence of local keypair
stat:
path: "{{ keypair_path }}"
register: keypair_local
- name: Delete remote keypair
ec2_key:
name: "{{ item.keypair_name }}"
state: absent
loop: "{{ molecule_yml.platforms }}"
loop_control:
index_var: index
when: not keypair_local.stat.exists
- name: Create keypair
ec2_key:
name: "{{ item.keypair_name }}"
loop: "{{ molecule_yml.platforms }}"
loop_control:
index_var: index
register: keypair
- name: Persist the keypair
copy:
dest: "{{ keypair_path }}"
content: "{{ keypair.results[0].key.private_key }}"
mode: 0600
when: keypair.changed
- name: Get the ec2 ami(s) by owner and name, if image not set
ec2_ami_facts:
owners: "{{ item.image_owner }}"
filters:
name: "{{ item.image_name }}"
loop: "{{ molecule_yml.platforms }}"
loop_control:
index_var: index
when: item.image is not defined
register: ami_facts
- name: Create molecule instance(s)
ec2:
key_name: "{{ item.keypair_name }}"
image: "{{ item.image
if item.image is defined
else (ami_facts.results[index].images | sort(attribute='creation_date', reverse=True))[0].image_id }}"
instance_type: "{{ item.instance_type }}"
vpc_subnet_id: "{{ item.vpc_subnet_id }}"
group: "{{ item.security_group_name }}"
instance_tags: "{{ item.instance_tags | combine({'instance': item.name})
if item.instance_tags is defined
else {'instance': item.name} }}"
wait: true
assign_public_ip: true
exact_count: 1
count_tag:
instance: "{{ item.name }}"
register: server
loop: "{{ molecule_yml.platforms }}"
loop_control:
index_var: index
async: 7200
poll: 0
- name: Wait for instance(s) creation to complete
async_status:
jid: "{{ item.ansible_job_id }}"
register: ec2_jobs
until: ec2_jobs.finished
retries: 300
with_items: "{{ server.results }}"
# Mandatory configuration for Molecule to function.
- name: Populate instance config dict
set_fact:
instance_conf_dict: {
'instance': "{{ item.instances[0].tags.instance }}",
'address': "{{ item.instances[0].public_ip }}",
'user': "{{ ssh_user }}",
'port': "{{ ssh_port }}",
'identity_file': "{{ keypair_path }}",
'instance_ids': "{{ item.instance_ids }}",
'group_id': "{{ security_group.results[0].group_id }}", }
with_items: "{{ ec2_jobs.results }}"
register: instance_config_dict
when: server.changed | bool
- 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.changed | bool
- name: Dump instance config
copy:
content: "{{ instance_conf | to_json | from_json | molecule_to_yaml | molecule_header }}"
dest: "{{ molecule_instance_config }}"
when: server.changed | bool
- name: Wait for SSH
wait_for:
port: "{{ ssh_port }}"
host: "{{ item.address }}"
search_regex: SSH
delay: 10
timeout: 320
with_items: "{{ lookup('file', molecule_instance_config) | molecule_from_yaml }}"
- name: Wait for boot process to finish
pause:
minutes: 2
provisonerセクション
provisonerセクションで指定された変数はconvergeの処理を上書きします。例えば元々group_vars/allに初期値となる変数の値が設定されていてそれを上書きしたい場合はこのprovisionerセクションから上書きします。
Moleculeの仕様上ansible-playbookの-eオプションのように変数をmoleculeコマンドから渡す機能は現在はありません。
そのため以下のように書くような事はできません
molecule test -e "var1=vaule1" -e "var2=vaule2"
varsファイル
通常のPlaybookを実行するようにvarsファイルへ変数を設定して各シナリオファイルで変数として読み込む事が可能です。
Moleculeでの「defaults/main.yml」、「group_vars/all」の扱い
defaults/main.yml
やgroup_vars/all
はRoleやPlaybookで利用される全体の変数を設定するファイルです。ただしMoleculeは外部Roleへはdefaults/main.yml
やgroup_vars/all
で指定した変数が渡らないため前述のprovisonerセクションに変数を記述します。
下記のコードはRoleで外部Roleを利用する際に外部Roleの変数を変更するときの一例です。
---
# 外部Roleの変数を「default/main.yml」で指定してもMoleculeから外部Roleには渡らない
external_roles_var_1: some_val
external_roles_var_2: some_val
external_roles_var_3: some_val
# 自身のRoleの変数は渡る
this_role_var_1: some_val
this_role_var_2: some_val
this_role_var_3: some_val
---
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: instance1
image: some_docker_image
provisioner:
name: ansible
connection_options:
# 外部Roleの変数はprovisionerセクションへ再度書く事になる
external_roles_var_1: some_val
external_roles_var_2: some_val
external_roles_var_3: some_val
---
- name: Converge
hosts: all
become: true
roles:
- external_role.some_role_name
- this_role
Moleculeで環境変数を渡す場合
Moleculeへ処理を渡すときに可変になる変数がある場合があります。例えばMoleculeが処理を実行するAMIのID、Dockerイメージ、クラウドの設定等です。
これはmolecule.ymlでディフォルト値を指定し例えば「env "var=vaule" molecule test」コマンドから渡す事が可能です。
例えばAWSで開発環境で利用するAMIやVPC Subnetを環境ごとに分けたい場合
---
dependency:
name: galaxy
driver:
name: ec2
platforms:
- name: instance
image: ${AMI_ID}
instance_type: t2.micro
vpc_subnet_id: ${VPC_SUBNET_ID}
.
.
.
.
.
このように記述すると環境変数からAMI IdやVPC Subnet Idを指定できるようになります。