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