Add linter for passing pkgs as list

This patch adds a new linter that ensures packages are being
passed as a list rather than using with_items. It also adds a
test for the new linter and adds the test to the existing linter
CI job script.

Change-Id: Iffd7284fb1c7cc41df2a4e271821e51bb274c3a3
This commit is contained in:
Major Hayden 2017-08-07 11:04:26 -05:00
parent 6e5b1d6a30
commit 580aa54b98
No known key found for this signature in database
GPG Key ID: 737051E0C1011FB1
4 changed files with 139 additions and 0 deletions

View File

@ -0,0 +1,81 @@
#!/usr/bin/env python
# Copyright 2017, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Ansible linter for passing packages as list to package modules."""
import os
import unittest
from ansiblelint import AnsibleLintRule, RulesCollection, Runner
TEST_PLAYBOOK_DIR = "{}/test/".format(
os.path.dirname(os.path.realpath(__file__))
)
PACKAGE_MODULES = [
'apt',
'dnf',
'package',
'pip',
'yum',
'zypper'
]
def is_package_action(task):
"""Test if task is using a package module."""
return task['action']['__ansible_module__'] in PACKAGE_MODULES
class PassListToPackageModules(AnsibleLintRule):
"""Ansible linter for passing packages as list to package modules."""
id = 'OSA0002'
shortdesc = 'Pass packages as a list to package modules'
description = (
"When passing multiple packages to a package module, pass the "
"packages as a list rather than using 'with_items'. This provides a "
"performance boost for deployments."
)
tags = ['performance']
def matchtask(self, file, task):
"""Search the task for our concerns."""
return is_package_action(task) and 'with_items' in task
class TestPassListToPackageModules(unittest.TestCase):
"""Test the PassListToPackageModules lint rule."""
collection = RulesCollection()
def setUp(self):
"""Set up the linter testing."""
self.collection.register(PassListToPackageModules())
def test_file_positive(self):
"""A valid playbook should pass the linter."""
playbook = '{}/package_module_pass_list.yml'.format(
TEST_PLAYBOOK_DIR
)
runner = Runner(self.collection, playbook, [], [], [])
self.assertEqual([], runner.run())
def test_file_negative(self):
"""An invalid playbook should fail the linter."""
playbook = '{}/package_module_with_items.yml'.format(
TEST_PLAYBOOK_DIR
)
runner = Runner(self.collection, playbook, [], [], [])
self.assertNotEqual([], runner.run())
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,27 @@
# Copyright 2017, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
---
- hosts: all
vars:
packages_to_install:
- bash
- tmux
- vim
tasks:
- name: Install packages using a list
package:
name: "{{ packages_to_install }}"
state: present

View File

@ -0,0 +1,28 @@
# Copyright 2017, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
---
- hosts: all
vars:
packages_to_install:
- bash
- tmux
- vim
tasks:
- name: Install packages using with_items
package:
name: "{{ item }}"
state: present
with_items: "{{ packages_to_install }}"

View File

@ -36,5 +36,8 @@ export COMMON_TESTS_PATH="${WORKING_DIR}/tests/common"
# Ensure that the Ansible environment is properly prepared
source "${COMMON_TESTS_PATH}/test-ansible-env-prep.sh"
# Run linter tests
python -m unittest discover -s ${WORKING_DIR}/ansible-lint/ -p "*.py"
# Execute ansible-lint
ansible-lint ${WORKING_DIR} -R -r ${WORKING_DIR}/ansible-lint/