Skip to content

Commit

Permalink
FEATURE: inital commit of the feature #53
Browse files Browse the repository at this point in the history
  • Loading branch information
pstauffer committed Mar 21, 2016
1 parent 6a53ae8 commit 24fc232
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 21 deletions.
32 changes: 31 additions & 1 deletion ansibleci/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,22 @@
# Basedir which should point to an Ansible project.
BASEDIR = os.getcwd()

# Roles directory paths, can be absolute or relative (to BASEDIR).
# Roles directory path(s), can be absolute or relative to BASEDIR.
ROLES = [
'roles/',
]

# Playbook directory path(s), can be absolute or relative to BASEDIR.
PLAYBOOKS = [
'plays/',
]

# File extensions, which are used for yml files in the ansible project directories.
YAML_FILE_EXENTSIONS = [
'yml',
'yaml',
]

#
# A list of tests to run.
#
Expand All @@ -29,6 +40,7 @@
'ansibleci.tests.readme.Readme',
'ansibleci.tests.handler.Handler',
'ansibleci.tests.tag.Tag',
'ansibleci.tests.deprecated.Deprecated',
]

#
Expand All @@ -54,3 +66,21 @@

# Should the tag name be identical with the role name?
TAG_ROLE_NAME = True


#
# Settings for ansibleci.tests.deprecated.
#

# A list with deprecated directives.
DEPRECATED_DIRECTIVES = [
'sudo',
'sudo_user',
'su',
'su_user',
]

DEPRECATED_RELEVANT_DIRECTORIES = [
'tasks',
'handlers',
]
87 changes: 67 additions & 20 deletions ansibleci/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,16 @@ def get_absolute_path(self, path):
else:
return os.path.abspath(os.path.join(self.config.BASEDIR, path))

def get_file_extension(self, file):
'''
Returns the file extension of a file. The ``file`` argument can be
a simple filename or a absoulte path.
'''
return '.'.join(os.path.basename(file).split('.')[1:])

def get_roles_paths(self):
'''
Returns all absolute paths to the roles/ directories, while considering
Returns all absolute paths to the role directories, while considering
the ``BASEDIR`` and ``ROLES`` config variables.
'''
roles = []
Expand All @@ -46,6 +53,18 @@ def get_roles_paths(self):

return roles

def get_playbook_paths(self):
'''
Returns all absolute paths to the playbook directories, while considering
the ``BASEDIR`` and ``PLAYBOOKS`` config variables.
'''
playbooks = []

for path in self.config.PLAYBOOKS:
playbooks.append(self.get_absolute_path(path))

return playbooks

def get_roles(self):
'''
Returns a key-value dict with a roles, while the key is the role name
Expand All @@ -71,6 +90,40 @@ def read_yaml(self, filename):
y = yaml.safe_load(d)
return y if y else {}

def verify_yaml_file(self, file_path):
'''
Return True or False, if the ``file_path`` is a file and the
file extension matchs the ``YAML_FILE_EXENTSIONS``.
'''
if os.path.isfile(file_path) and self.get_file_extension(file_path) in self.config.YAML_FILE_EXENTSIONS:
return True
else:
return False

def get_yaml_files(self, dir_path, recursive=False):
'''
Returns a list of all yaml files in a directory.
'''
result = []

if not os.path.isdir(dir_path):
return []

if recursive:
for root, dirname, filenames in os.walk(dir_path):
for filename in filenames:
file_path = os.path.join(root, filename)
if self.verify_yaml_file(file_path):
result.append(file_path)
return result

else:
for filename in os.listdir(dir_path):
file_path = os.path.join(dir_path, filename)
if self.verify_yaml_file(file_path):
result.append(file_path)
return result

def get_yaml_items(self, dir_path, param=None):
'''
Loops through the dir_path and parses all YAML files inside the
Expand All @@ -80,27 +133,21 @@ def get_yaml_items(self, dir_path, param=None):
in a list. If a param is defined, then all items will be scanned for
this param and a list of all those values will be returned.
'''

result = []

if not os.path.isdir(dir_path):
return []

for filename in os.listdir(dir_path):

path = os.path.join(dir_path, filename)
items = self.read_yaml(path)

for item in items:
if param:
if param in item:
item = item[param]
if isinstance(item, list):
result.extend(item)
else:
result.append(item)
else:
result.append(item)
for filename in self.get_yaml_files(dir_path):
items = self.read_yaml(filename)

for item in items:
if param:
if param in item:
item = item[param]
if isinstance(item, list):
result.extend(item)
else:
result.append(item)
else:
result.append(item)

return result

Expand Down
71 changes: 71 additions & 0 deletions ansibleci/tests/deprecated.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2015 confirm IT solutions
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

from ansibleci.test import Test
import os


class Deprecated(Test):
'''
Test to check if deprecated directives (i.e. ``su``) are used in the Ansible project.
All yml files in some defined directories in the Ansible project will be checked for
deprecated directives. The file extension for the yaml files can be configured.
'''

def run(self):
'''
Run method which will be called by the framework.
'''
self.config = self.get_config()
self.helper = self.get_helper()

self.directives = self.config.DEPRECATED_DIRECTIVES

roles = self.helper.get_roles().iteritems()
playbooks = self.helper.get_playbook_paths()

for playbook in playbooks:
self.check_directives(playbook)

for name, path in roles:
for subdir in self.config.DEPRECATED_RELEVANT_DIRECTORIES:
self.check_directives(os.path.join(path, subdir))

def check_directives(self, dir_path):
'''
Check all files in a path for deprecated directies.
'''
for check_file in self.helper.get_yaml_files(dir_path, recursive=True):
counter = self.initialize_counter()
for item in self.helper.read_yaml(check_file):
for directive in self.directives:
if directive in item:
counter[directive] += 1

count = counter[directive]
kwargs = {
'check_file': check_file,
'directive': directive,
'count': count
}
if count == 0:
self.passed('Directive {directive} exists not in the file {check_file}'.format(**kwargs))
elif count == 1:
self.failed('Directive {directive} exists {count} time in the file {check_file}'.format(**kwargs))
else:
self.failed('Directive {directive} exists {count} times in the file {check_file}'.format(**kwargs))

def initialize_counter(self):
'''
Initialize a counter for the directives.
'''
counter = {}
for directive in self.directives:
counter[directive] = 0
return counter

0 comments on commit 24fc232

Please sign in to comment.