Created
May 9, 2017 07:42
-
-
Save Spredzy/4278cfaba5f12b834bc530fe0a4fed2f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/cli/__init__.py b/cli/__init__.py | |
index ce51245..fea8c0a 100644 | |
--- a/cli/__init__.py | |
+++ b/cli/__init__.py | |
@@ -146,7 +146,7 @@ class CLI(with_metaclass(ABCMeta, object)): | |
Actually runs a child defined method using the execute_<action> pattern | |
""" | |
fn = getattr(self, "execute_%s" % self.action) | |
- fn() | |
+ return fn() | |
@abstractmethod | |
def run(self): | |
diff --git a/cli/galaxy.py b/cli/galaxy.py | |
index 3b0192d..bec5c22 100644 | |
--- a/cli/galaxy.py | |
+++ b/cli/galaxy.py | |
@@ -53,7 +53,7 @@ class GalaxyCLI(CLI): | |
'''command to manage Ansible roles in shared repostories, the default of which is Ansible Galaxy *https://galaxy.ansible.com*.''' | |
SKIP_INFO_KEYS = ("name", "description", "readme_html", "related", "summary_fields", "average_aw_composite", "average_aw_score", "url" ) | |
- VALID_ACTIONS = ("delete", "import", "info", "init", "install", "list", "login", "remove", "search", "setup") | |
+ VALID_ACTIONS = ("delete", "import", "info", "init", "install", "list", "login", "remove", "search", "setup", "validate") | |
def __init__(self, args): | |
self.api = None | |
@@ -110,9 +110,11 @@ class GalaxyCLI(CLI): | |
self.parser.add_option('--remove', dest='remove_id', default=None, | |
help='Remove the integration matching the provided ID value. Use --list to see ID values.') | |
self.parser.add_option('--list', dest="setup_list", action='store_true', default=False, help='List all of your integrations.') | |
+ elif self.action == "validate": | |
+ self.parser.set_usage("usage: %prog validate [options] role_name") | |
# options that apply to more than one action | |
- if self.action in ['init', 'info']: | |
+ if self.action in ['init', 'info', 'validate']: | |
self.parser.add_option( '--offline', dest='offline', default=False, action='store_true', help="Don't query the galaxy API when creating roles") | |
if self.action not in ("delete","import","init","login","setup"): | |
@@ -150,7 +152,7 @@ class GalaxyCLI(CLI): | |
super(GalaxyCLI, self).run() | |
self.api = GalaxyAPI(self.galaxy) | |
- self.execute() | |
+ return self.execute() | |
def exit_without_ignore(self, rc=1): | |
""" | |
@@ -185,6 +187,27 @@ class GalaxyCLI(CLI): | |
# execute actions | |
############################ | |
+ def execute_validate(self): | |
+ """ | |
+ Runs functions that validates the compliance of a role to be uploaded to Galaxy. | |
+ """ | |
+ | |
+ role = None | |
+ role_name = self.args.pop(0).strip() if self.args else None | |
+ roles_path = self.get_opt('roles_path') | |
+ | |
+ for role_path in roles_path: | |
+ if os.path.exists('%s/%s' % (role_path, role_name)): | |
+ role = GalaxyRole(self.galaxy, role_name, | |
+ path='%s/%s' % (role_path, role_name)) | |
+ break | |
+ if not role: | |
+ if os.path.exists(role_name): | |
+ role = GalaxyRole(self.galaxy, role_name, | |
+ path='%s' % role_name) | |
+ | |
+ return 0 if role.is_valid() else 1 | |
+ | |
def execute_init(self): | |
""" | |
creates the skeleton framework of a role that complies with the galaxy metadata format. | |
diff --git a/galaxy/role.py b/galaxy/role.py | |
index 369c66d..b8b46dd 100644 | |
--- a/galaxy/role.py | |
+++ b/galaxy/role.py | |
@@ -23,6 +23,8 @@ from __future__ import (absolute_import, division, print_function) | |
__metaclass__ = type | |
import datetime | |
+import glob | |
+import json | |
import os | |
import tarfile | |
import tempfile | |
@@ -364,3 +366,103 @@ class GalaxyRole(object): | |
} | |
""" | |
return dict(scm=self.scm, src=self.src, version=self.version, name=self.name) | |
+ | |
+ def is_valid(self): | |
+ """ | |
+ Run sanity check validation to ensure role is compliant with what is expected on Galaxy side | |
+ """ | |
+ | |
+ results = [] | |
+ | |
+ # ROLE001 | |
+ role001_result = { | |
+ 'name': 'ROLE001', | |
+ 'description': 'Role has a meta/mail.yml file', | |
+ 'optional': False, | |
+ 'pass': os.path.exists('%s/meta/main.yml' % self.path) | |
+ } | |
+ results.append(role001_result) | |
+ | |
+ # ROLE002 | |
+ role002_result = { | |
+ 'name': 'ROLE002', | |
+ 'description': 'A LICENSE file is present in the role directory', | |
+ 'optional': True, | |
+ 'pass': os.path.exists('%s/LICENSE' % self.path) | |
+ } | |
+ results.append(role002_result) | |
+ | |
+ # ROLE003 | |
+ role003_result = { | |
+ 'name': 'ROLE003', | |
+ 'optional': False, | |
+ 'description': 'A README.md file is present in the role directory', | |
+ 'pass': os.path.exists('%s/README.md' % self.path) | |
+ } | |
+ results.append(role003_result) | |
+ | |
+ # ROLE004 | |
+ meta = yaml.load(open('%s/meta/main.yml' % self.path).read()) | |
+ keys = ['author', 'description', 'license', 'min_ansible_version'] | |
+ role004_result = { | |
+ 'name': 'ROLE004', | |
+ 'description': 'meta/main.yml contains basic necessary informations', | |
+ 'optional': False, | |
+ 'pass': set(keys) <= set(meta['galaxy_info'].keys()) | |
+ } | |
+ results.append(role004_result) | |
+ | |
+ # ROLE005 | |
+ variables = {} | |
+ role_name = os.path.basename(self.path) | |
+ if role_name.startswith('ansible-role-'): | |
+ role_name = role_name.replace('ansible-role-', '') | |
+ role_name = role_name.replace('-', '_') | |
+ if os.path.isdir('%s/vars'): | |
+ for filename in glob.glob('*.yml'): | |
+ variables.update(yaml.load(open(filename, 'r').read())) | |
+ if os.path.isdir('%s/defaults' % self.path): | |
+ for filename in glob.glob('%s/defaults/*.yml' % self.path): | |
+ variables.update(yaml.load(open(filename, 'r').read())) | |
+ | |
+ role005_result = { | |
+ 'name': 'ROLE005', | |
+ 'description': 'Variables in defaults/ and vars/ are preceded by role name: %s' % role_name, | |
+ 'optional': True, | |
+ 'pass': not len( | |
+ [v for v in variables.keys() if not v.startswith(role_name)] | |
+ ) | |
+ } | |
+ results.append(role005_result) | |
+ | |
+ # ROLE006 | |
+ # TODO(spredzy): Handle the complex dependency format | |
+ # | |
+ if not self.options.offline: | |
+ meta = yaml.load(open('%s/meta/main.yml' % self.path).read()) | |
+ result = True | |
+ fail_deps = [] | |
+ if 'dependencies' in meta and meta['dependencies']: | |
+ for dep in meta['dependencies']: | |
+ url = 'https://galaxy.ansible.com/api/v1/roles/?namespace=%s&name=%s&format=json' % (dep.split('.')[0], dep.split('.')[1]) | |
+ if json.loads(open_url(url).read())['count'] == 0: | |
+ fail_deps.append(dep) | |
+ | |
+ result = not len(fail_deps) | |
+ role006_result = { | |
+ 'name': 'ROLE006', | |
+ 'optional': False, | |
+ 'description': 'The dependencies listed in meta/main.yml are in Galaxy', | |
+ 'pass': result | |
+ } | |
+ results.append(role006_result) | |
+ | |
+ failed_results = [result for result in results if result['pass'] is False] | |
+ is_valid = not len(failed_results) | |
+ | |
+ if is_valid: | |
+ display.v(str(results)) | |
+ else: | |
+ display.display(str(failed_results)) | |
+ | |
+ return is_valid |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment