blob: 06bdc5b6ff11d24be20ba2b141e0c50172ea2fd2 [file] [log] [blame]
Samuli Silvius542bdfd2019-03-19 13:40:50 +02001.. This work is licensed under a Creative Commons Attribution 4.0 International License.
2.. http://creativecommons.org/licenses/by/4.0
Bartek Grzybowski9f7a2ac2021-03-22 13:48:10 +01003.. Copyright 2021 Samsung Electronics Co., Ltd.
Samuli Silvius542bdfd2019-03-19 13:40:50 +02004
Bartek Grzybowski9f7a2ac2021-03-22 13:48:10 +01005Offline Installer Testing Guide
6^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Samuli Silvius542bdfd2019-03-19 13:40:50 +02007
8This testing guide describes how offline installer can be tested in local
9development environment (laptop) without the need for actual servers.
10
11Documentation refers to files/directories in ``ansible`` directory of this repository.
12
13Introduction
14============
15
16Offline installer uses Molecule_ for testing all roles.
17
18Molecule is tool for ansible roles development and testing. In this project
19Molecule is used for integration type of testing for both roles and playbooks.
20Role code is tested against simulated host.
21
22Molecule is designed to test single Ansible_ role in isolation. Offline installer however
23has many small roles that are dependent on each other and also execution order for roles
24is meaningful. In that respect Molecule's design does not offer sufficient level
25of testing as it's lacking playbook level of scenario testing by default.
26Luckily Molecule is highly configurable and it is possible to achieve a higher level of
27testing scenarios for the offline installer.
28
29Testing with Molecule is divided to two levels of testing:
30 1) role level testing (as per Molecule design)
31 2) playbook level testing (offline installer own setup)
32
33Purpose
34=======
35
36The purpose of using testing framework like Molecule is to make possible for developer to
37verify ansible code changes locally in own laptop without the need for big resources.
38
39Developer is also expected to do development of the Ansible code and the Molecule test
40code at the same time.
41Offline installer does not have unittest level of testing for the ansible code.
42
43Any commit made to ansible code base needs to first pass Molecule tests before
44it's merged.
45
46Test levels
47===========
48
49To cover both testing levels (role and playbook) with maximum benefit and minimum
50copy-pasting, the testing code should be written in reusable way.
51
52Reusable test code can be achieved by writing all prepare/cleanup and other
53helping code as a roles into main test directory.
54Also testinfra_ test code can be shared between different roles and between different scenarios
55of one role.
56
57Testing of role and one scenario (one execution run of molecule) is fully
58defined by **molecule.yml** file.
59
60molecule.yml file is always located in directory:
61
62 <tested-role>/molecule/<scenario>/molecule.yml
63
64i.e. one role can have multiple scenarios (different configuration, OS etc. whatever user wants)
65to execute tests for same role. Each scenario has own molecule.yml file and own testinfra
66tests.
67
68Molecule.yml file is the only file that cannot be re-used (except with symbolic links) but
69all other resources can be reused by referencing those in molecule.yml file or/and indirectly
70from resources molecule.yml is pointing to.
71
72**tested-role** is clear in case of normal role level testing, but in playbook level testing the
73tested-role is just an invented role name and directory with molecule directory inside but no
74actual ansible role code.
75
76Role level testing
77------------------
78
79The target is to test single role in isolation just like Molecule is designed.
80Role level testing is supposed to cover:
81
82- Syntax checking (Yamllint_, `Ansible lint`_, flake8_)
83- Ansible code testing
84- Idempotence testing
85- Verifying role results from target hosts (testinfra tests)
86
87Ansible code testing can/should also cover all different options how this role
88can be run (`scenario <https://molecule.readthedocs.io/en/latest/configuration.html#root-scenario>`_).
89Different molecule runs can be implemented as own scenarios (in addition to default scenario)
90or default scenario playbook can be extended to run role tests multiple times just adjusting
91configuration between.
92
Bartek Grzybowskic265b832019-04-09 13:22:43 +020093Single scenario example with nexus role
Bartek Grzybowski9f7a2ac2021-03-22 13:48:10 +010094
Samuli Silvius542bdfd2019-03-19 13:40:50 +020095::
96
97 ├── infrastructure.yml
98 ├── roles
99 │   ├── nexus
100 │   │   ├── defaults
101 │   │   ├── files
102 │   │   ├── molecule
103 │   │   │   └── default
104 │   │   │   ├── molecule.yml
105 │   │   │   ├── playbook.yml
106 │   │   │   ├── prepare.yml
107 │   │   │   └── tests
108 │   │   ├── tasks
109 │   │   └── vars
110
Bartek Grzybowskic265b832019-04-09 13:22:43 +0200111Multiple scenario example with chrony role
Bartek Grzybowski9f7a2ac2021-03-22 13:48:10 +0100112
Bartek Grzybowskic265b832019-04-09 13:22:43 +0200113::
114
115 roles/chrony
116 ├── defaults
117 │   └── main.yml
118 ├── handlers
119 │   └── main.yml
120 ├── molecule
121 │   ├── default
122 │   │   ├── molecule.yml
123 │   │   ├── playbook.yml
124 │   │   └── prepare.yml
125 │   └── ubuntu
126 │   └── molecule.yml
127 ├── tasks
128 │   └── main.yml
129 └── templates
130 └── chrony.conf.j2
131
132By default molecule runs just default scenario. To run specific one ``-s <scenario name>``
133option must be used. The only subcommands supporting ``--all`` switch for playing with
134all scenarios are ``test`` and ``destroy``. If using other ones ``-s`` must be used.
135
136The cross-scenario code reuse paradigm should be rather implemented inside particular
137scenario's ``molecule.yml`` file than by using filesystem symlinks. All provisioner
138playbooks should be located in default scenarios directory then and referenced in
139alternative scenarios as follows
140::
141
142 provisioner:
143 name: ansible
144 lint:
145 name: ansible-lint
146 env:
147 ANSIBLE_ROLES_PATH: ../../../../test/roles
148 playbooks:
149 prepare: ../default/prepare.yml
150 converge: ../default/playbook.yml
151
Samuli Silvius542bdfd2019-03-19 13:40:50 +0200152Playbook level testing
153----------------------
154
155Playbook level testing is this project's (offline installer) own
156setup and way of using Molecule. The target is to raise testing level
157from single role testing up to single playbook testing.
158
159Playbook level testing can be used also to run multiple playbooks and/or
160playbooks multiple times with different configuration.
161
162The aim is to verify multiple roles working together i.e. higher level of
163integration testing.
164
165Practically the **tested-role** is just a wrapper directory to conform
166molecule required directory structure and provide a name for the test.
167Directory itself does not contain any ansible role code, but just
168molecule files configured to run multiple other roles.
169
170Playbook level test directories should be named consistently according to
171tested playbook and prefix string ``play`` and with optional description
172if there are multiple scenarios for single playbook:
173
174 play-<playbookname>[-<description>]
175
176E.g.
177
178- ``play-infrastructure``
179- ``play-resources``
180
181As role's are tested with own molecule tests in isolation, playbook level tests
182should focus to integration of the roles and should avoid of repeating same tests
183as done already for individual roles.
184
185Playbook level testing is supposed to cover:
186 - Ansible code testing
187
188Basically it's easier to highlight what is supposed to be **avoided** in playbook level
189testing for the reason not to repeat the same that is done already in role level testing.
190
191- Syntax checking is left out already by default as molecule does linting only for the
192 role code where molecule is run, and in this case tested-role is empty.
193
194- Idempotence can be tested, but should be disabled (by default) in molecule.yml because
195 it takes too much time and was tested already for individual roles.
196
197- Verifying target hosts with testinfra tests can be done but then something else
198 should be tested as in role based tests. And if those 2 would overlap it's better
199 to leave them out.
200
201Example with infrastructure playbook level test files
Bartek Grzybowski9f7a2ac2021-03-22 13:48:10 +0100202
Samuli Silvius542bdfd2019-03-19 13:40:50 +0200203::
204
205 ├── infrastructure.yml
206 └── test
207 ├── play-infrastructure
208 │   └── molecule
209 │   └── default
210 │   ├── molecule.yml
211 │   ├── playbook.yml
212 │   ├── prepare.yml
213 │   └── tests
214
215Test code reuse and naming
216===========================
217
218As both testing levels test the same Ansible roles, there are a need
219to share common code for both of them.
220
221Testinfra_ Python code should be shared when also playbook level
222tests verify target hosts. However sharing is not limited only for the 2 test levels
223but also between different roles.
224
225Individual role have testinfra tests on directory:
226
227 roles/<role>/molecule/<scenario>/tests
228
229and any commonly usable testinfra Python code should be placed to directory:
230
231 test/testinfra
232
233Ansible role testing uses several resources defined by provisioner section of
234molecule.yml
235https://molecule.readthedocs.io/en/latest/configuration.html#provisioner
236
237Most common resources that are written for role testing are:
238
239- playbook.yml (mandatory but can include specific code)
240- prepare.yml
241- cleanup.yml
242- create.yml
243- destroy.yml
244
245all of which can be just placed to scenario directory together with playbook.yml
246(without editing molecule.yml when in default directory) and all of which can
247include ansible code to do something e.g. prepare role for testing.
248
249Example molecule files:
250
251Role level tests for nexus role:
252 - roles/nexus/molecule/default/molecule.yml
253 - roles/nexus/molecule/default/playbook.yml
254 - roles/nexus/molecule/default/prepare.yml
255playbook level tests for infrastructure playbook:
256 - test/play-infrastructure/molecule/default/molecule.yml
257 - test/play-infrastructure/molecule/default/playbook.yml
258 - test/play-infrastructure/molecule/default/prepare.yml
259
260Sharing all test code should be done by writing them in the form of ansible
261roles and placing commonly usable roles into:
262
263 test/roles/<testrole>
264
265Test roles should be named consistently according to action it's needed and
266role for it's for together with optional description:
267
268 <action>-<role>[-<description>]
269
270Examples of commonly used test roles
Bartek Grzybowski9f7a2ac2021-03-22 13:48:10 +0100271
Samuli Silvius542bdfd2019-03-19 13:40:50 +0200272::
273
274 ├── infrastructure.yml
275 └── test
276 ├── play-infrastructure
277 └── roles
278 ├── post-certificates
279 ├── prepare-common
280 ├── prepare-dns
281 ├── prepare-docker
282 ├── prepare-nexus
283 └── prepare-nginx
284
285Molecule platform images
286========================
287
288Molecule can build images of the tested hosts on the fly with default
289Dockerfile template (docker driver) or from a Dockerfile provided by user.
290In case of Vagrant driver used box image can be also fully customized by user.
291
Bartek Grzybowskic265b832019-04-09 13:22:43 +0200292To speed up testing and lessen the footprint of code for image preparation it's
293preferred to use unmodified images from Docker Registry whenever possible (can be
294pulled prior to running Molecule) or pre-build images created from Dockerfiles
295listed below. Most significant feature of those is support for Systemd, so they
296should be used in cases where ansible's 'systemd' module is used.
Samuli Silvius542bdfd2019-03-19 13:40:50 +0200297
298Used Dockerfiles/Box definitions are kept in following directory structure
Bartek Grzybowski9f7a2ac2021-03-22 13:48:10 +0100299
Samuli Silvius542bdfd2019-03-19 13:40:50 +0200300::
301
302 └── test
303 └── images
304 ├── docker
305 │   ├── build-all.sh
306 │   ├── centos7
307 │   │   ├── build.sh
Samuli Silvius542bdfd2019-03-19 13:40:50 +0200308 │   │   └── Dockerfile
309 │   └── ubuntu
310 │   ├── build.sh
311 │   └── Dockerfile
312 └── vagrant
313
Bartek Grzybowskic265b832019-04-09 13:22:43 +0200314``Build-all.sh`` is a script for building all images, ``build.sh`` scripts in
315particular platforms subdirs are for building just specific images. Keep in mind
316that while images from Docker Registry will be downloaded automatically at run
317time, the above ones **must** be built manually prior to launching Molecule.
318
Samuli Silvius542bdfd2019-03-19 13:40:50 +0200319Build images
320------------
321
322Build all platforms images before running Molecule tests. Building can be done
323with the following single command:
324
325 test/images/docker/build-all.sh
326
327Install
328=======
329
330Molecule can be installed in multiple ways and in this guide 2 different ways is
331covered.
332
333- Install Molecule with pip in virtual environment
334- Use Molecule provided docker container to run Molecule
335
336Install with pip
337----------------
338
339This is a OS dependent and some prerequisites needs to be installed, but after
340prerequisites are installed installing Molecule can be done by calling following
341script:
342
343 source test/bin/install-molecule.sh
344
345As for the required OS packages, see example for Ubuntu in the install-molecule.sh
346script's comments or from Molecule_ pages.
347
348Note that sourcing the script is not needed to get Molecule installed but it leaves
349you already into virtual environment and ready to run Molecule.
350
351To get out from virtual environment issue:
352
353 deactivate
354
355And next time to activate virtual environment again before running Molecule, issue:
356
357 source ~/molecule_venv/bin/activate
358
359And here the directory ``~/molecule_venv`` is just the default virtual environment
360path that install-molecule.sh script is using and can be overridden with
361``VENV_PATH`` environment variable.
362
363Use Molecule docker container
364-----------------------------
365
366Molecule provides docker containers images via quay.io_ where Molecule, Ansible
367and all needed dependencies are build to the image.
368
369In this way of using Molecule, no installation is needed and only docker is the
370prerequisite for running Molecule.
371
372For using provided image to test offline-installer roles, following scripts are
373provided:
374
375Build container image:
376 ``test/molecule-docker/build.sh``
377
378This will build image named ``molecule-dev`` with strict version tag.
379
380Set molecule into the PATH:
381 ``source test/bin/set_molecule_paths.sh``
382
383That will add the actual Molecule run wrapper script test/bin/molecule.sh to path
384usable from everywhere similarly than molecule with pip and virtual environment.
385
386Run Molecule wrapper script:
387 ``test/bin/molecule.sh``
388
389For running Molecule. Using ``molecule-dev`` image and the exact version defined by
390test/docker/build.sh script.
391
392Usage
393=====
394
395Basic usage of molecule tests. See more detailed instructions from Molecule_
396
397Run complete testing for a role or a playbook:
398
3991. cd roles/<role> or cd test/play-<playbook-name>
4002. molecule test
401
402Develop a role code and run testing during the coding:
403
4041. cd roles/<role>
4052. Edit ansible code and molecule test code when needed
4063. molecule converge
4074. Repeat steps 2 and 3 until code is ready and molecule tests are passing
4085. molecule test
409
410.. _Molecule: https://molecule.readthedocs.io
411.. _quay.io: https://quay.io/repository/ansible/molecule
412.. _Testinfra: https://testinfra.readthedocs.io
413.. _Flake8: http://flake8.pycqa.org
414.. _Yamllint: https://github.com/adrienverge/yamllint
415.. _Ansible Lint: https://github.com/ansible/ansible-lint
416.. _Ansible: https://www.ansible.com/