galaxy updates
better error reporting on fetching errors use scm if it exists over src unified functions in requirements simplified logic added verbose to tests cleanup code refs, unused options and dead code moved get_opt to base class fixes #11920 fixes #12612 fixes #10454
This commit is contained in:
parent
a3ed9fc131
commit
f73329401b
7 changed files with 288 additions and 316 deletions
|
@ -512,3 +512,16 @@ class CLI(object):
|
||||||
|
|
||||||
return vault_pass
|
return vault_pass
|
||||||
|
|
||||||
|
def get_opt(self, k, defval=""):
|
||||||
|
"""
|
||||||
|
Returns an option from an Optparse values instance.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
data = getattr(self.options, k)
|
||||||
|
except:
|
||||||
|
return defval
|
||||||
|
if k == "roles_path":
|
||||||
|
if os.pathsep in data:
|
||||||
|
data = data.split(os.pathsep)[0]
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,6 @@ from distutils.version import LooseVersion
|
||||||
from jinja2 import Environment
|
from jinja2 import Environment
|
||||||
|
|
||||||
import ansible.constants as C
|
import ansible.constants as C
|
||||||
import ansible.utils
|
|
||||||
import ansible.galaxy
|
|
||||||
from ansible.cli import CLI
|
from ansible.cli import CLI
|
||||||
from ansible.errors import AnsibleError, AnsibleOptionsError
|
from ansible.errors import AnsibleError, AnsibleOptionsError
|
||||||
from ansible.galaxy import Galaxy
|
from ansible.galaxy import Galaxy
|
||||||
|
@ -126,19 +124,6 @@ class GalaxyCLI(CLI):
|
||||||
|
|
||||||
self.execute()
|
self.execute()
|
||||||
|
|
||||||
def get_opt(self, k, defval=""):
|
|
||||||
"""
|
|
||||||
Returns an option from an Optparse values instance.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
data = getattr(self.options, k)
|
|
||||||
except:
|
|
||||||
return defval
|
|
||||||
if k == "roles_path":
|
|
||||||
if os.pathsep in data:
|
|
||||||
data = data.split(os.pathsep)[0]
|
|
||||||
return data
|
|
||||||
|
|
||||||
def exit_without_ignore(self, rc=1):
|
def exit_without_ignore(self, rc=1):
|
||||||
"""
|
"""
|
||||||
Exits with the specified return code unless the
|
Exits with the specified return code unless the
|
||||||
|
@ -147,40 +132,6 @@ class GalaxyCLI(CLI):
|
||||||
if not self.get_opt("ignore_errors", False):
|
if not self.get_opt("ignore_errors", False):
|
||||||
raise AnsibleError('- you can use --ignore-errors to skip failed roles and finish processing the list.')
|
raise AnsibleError('- you can use --ignore-errors to skip failed roles and finish processing the list.')
|
||||||
|
|
||||||
def parse_requirements_files(self, role):
|
|
||||||
if 'role' in role:
|
|
||||||
# Old style: {role: "galaxy.role,version,name", other_vars: "here" }
|
|
||||||
role_info = role_spec_parse(role['role'])
|
|
||||||
if isinstance(role_info, dict):
|
|
||||||
# Warning: Slight change in behaviour here. name may be being
|
|
||||||
# overloaded. Previously, name was only a parameter to the role.
|
|
||||||
# Now it is both a parameter to the role and the name that
|
|
||||||
# ansible-galaxy will install under on the local system.
|
|
||||||
if 'name' in role and 'name' in role_info:
|
|
||||||
del role_info['name']
|
|
||||||
role.update(role_info)
|
|
||||||
else:
|
|
||||||
# New style: { src: 'galaxy.role,version,name', other_vars: "here" }
|
|
||||||
if 'github.com' in role["src"] and 'http' in role["src"] and '+' not in role["src"] and not role["src"].endswith('.tar.gz'):
|
|
||||||
role["src"] = "git+" + role["src"]
|
|
||||||
|
|
||||||
if '+' in role["src"]:
|
|
||||||
(scm, src) = role["src"].split('+')
|
|
||||||
role["scm"] = scm
|
|
||||||
role["src"] = src
|
|
||||||
|
|
||||||
if 'name' not in role:
|
|
||||||
role["name"] = GalaxyRole.url_to_spec(role["src"])
|
|
||||||
|
|
||||||
if 'version' not in role:
|
|
||||||
role['version'] = ''
|
|
||||||
|
|
||||||
if 'scm' not in role:
|
|
||||||
role['scm'] = None
|
|
||||||
|
|
||||||
return role
|
|
||||||
|
|
||||||
|
|
||||||
def _display_role_info(self, role_info):
|
def _display_role_info(self, role_info):
|
||||||
|
|
||||||
text = "\nRole: %s \n" % role_info['name']
|
text = "\nRole: %s \n" % role_info['name']
|
||||||
|
@ -298,9 +249,8 @@ class GalaxyCLI(CLI):
|
||||||
data = ''
|
data = ''
|
||||||
for role in self.args:
|
for role in self.args:
|
||||||
|
|
||||||
role_info = {}
|
role_info = {'role_path': roles_path}
|
||||||
gr = GalaxyRole(self.galaxy, role)
|
gr = GalaxyRole(self.galaxy, role)
|
||||||
#self.galaxy.add_role(gr)
|
|
||||||
|
|
||||||
install_info = gr.install_info
|
install_info = gr.install_info
|
||||||
if install_info:
|
if install_info:
|
||||||
|
@ -351,54 +301,45 @@ class GalaxyCLI(CLI):
|
||||||
|
|
||||||
no_deps = self.get_opt("no_deps", False)
|
no_deps = self.get_opt("no_deps", False)
|
||||||
force = self.get_opt('force', False)
|
force = self.get_opt('force', False)
|
||||||
roles_path = self.get_opt("roles_path")
|
|
||||||
|
|
||||||
roles_done = []
|
|
||||||
roles_left = []
|
roles_left = []
|
||||||
if role_file:
|
if role_file:
|
||||||
self.display.debug('Getting roles from %s' % role_file)
|
|
||||||
try:
|
try:
|
||||||
self.display.debug('Processing role file: %s' % role_file)
|
|
||||||
f = open(role_file, 'r')
|
f = open(role_file, 'r')
|
||||||
if role_file.endswith('.yaml') or role_file.endswith('.yml'):
|
if role_file.endswith('.yaml') or role_file.endswith('.yml'):
|
||||||
try:
|
for role in yaml.safe_load(f.read()):
|
||||||
rolesparsed = map(self.parse_requirements_files, yaml.safe_load(f))
|
self.display.debug('found role %s in yaml file' % str(role))
|
||||||
except Exception as e:
|
if 'name' not in role:
|
||||||
raise AnsibleError("%s does not seem like a valid yaml file: %s" % (role_file, str(e)))
|
if 'src' in role:
|
||||||
roles_left = [GalaxyRole(self.galaxy, **r) for r in rolesparsed]
|
role['name'] = RoleRequirement.repo_url_to_role_name(role['src'])
|
||||||
else:
|
else:
|
||||||
|
raise AnsibleError("Must specify name or src for role")
|
||||||
|
roles_left.append(GalaxyRole(self.galaxy, **role))
|
||||||
|
else:
|
||||||
|
self.display.deprecated("going forward only the yaml format will be supported")
|
||||||
# roles listed in a file, one per line
|
# roles listed in a file, one per line
|
||||||
self.display.deprecated("Non yaml files for role requirements")
|
for rline in f.readlines():
|
||||||
for rname in f.readlines():
|
self.display.debug('found role %s in text file' % str(rline))
|
||||||
if rname.startswith("#") or rname.strip() == '':
|
roles_left.append(GalaxyRole(self.galaxy, **RoleRequirement.role_spec_parse(rline)))
|
||||||
continue
|
|
||||||
roles_left.append(GalaxyRole(self.galaxy, rname.strip()))
|
|
||||||
f.close()
|
f.close()
|
||||||
except (IOError,OSError) as e:
|
except (IOError, OSError) as e:
|
||||||
raise AnsibleError("Unable to read requirements file (%s): %s" % (role_file, str(e)))
|
self.display.error('Unable to open %s: %s' % (role_file, str(e)))
|
||||||
else:
|
else:
|
||||||
# roles were specified directly, so we'll just go out grab them
|
# roles were specified directly, so we'll just go out grab them
|
||||||
# (and their dependencies, unless the user doesn't want us to).
|
# (and their dependencies, unless the user doesn't want us to).
|
||||||
for rname in self.args:
|
for rname in self.args:
|
||||||
roles_left.append(GalaxyRole(self.galaxy, rname.strip()))
|
roles_left.append(GalaxyRole(self.galaxy, rname.strip()))
|
||||||
|
|
||||||
while len(roles_left) > 0:
|
for role in roles_left:
|
||||||
|
self.display.debug('Installing role %s ' % role.name)
|
||||||
# query the galaxy API for the role data
|
# query the galaxy API for the role data
|
||||||
role_data = None
|
role_data = None
|
||||||
role = roles_left.pop(0)
|
role = roles_left.pop(0)
|
||||||
role_path = role.path
|
|
||||||
|
|
||||||
if role.install_info is not None and not force:
|
if role.install_info is not None and not force:
|
||||||
self.display.display('- %s is already installed, skipping.' % role.name)
|
self.display.display('- %s is already installed, skipping.' % role.name)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if role_path:
|
|
||||||
self.options.roles_path = role_path
|
|
||||||
else:
|
|
||||||
self.options.roles_path = roles_path
|
|
||||||
|
|
||||||
self.display.debug('Installing role %s from %s' % (role.name, self.options.roles_path))
|
|
||||||
|
|
||||||
tmp_file = None
|
tmp_file = None
|
||||||
installed = False
|
installed = False
|
||||||
if role.src and os.path.isfile(role.src):
|
if role.src and os.path.isfile(role.src):
|
||||||
|
@ -407,7 +348,7 @@ class GalaxyCLI(CLI):
|
||||||
else:
|
else:
|
||||||
if role.scm:
|
if role.scm:
|
||||||
# create tar file from scm url
|
# create tar file from scm url
|
||||||
tmp_file = GalaxyRole.scm_archive_role(role.scm, role.src, role.version, role.name)
|
tmp_file = RoleRequirement.scm_archive_role(role.scm, role.src, role.version, role.name)
|
||||||
if role.src:
|
if role.src:
|
||||||
if '://' not in role.src:
|
if '://' not in role.src:
|
||||||
role_data = self.api.lookup_role_by_name(role.src)
|
role_data = self.api.lookup_role_by_name(role.src)
|
||||||
|
@ -438,11 +379,14 @@ class GalaxyCLI(CLI):
|
||||||
# download the role. if --no-deps was specified, we stop here,
|
# download the role. if --no-deps was specified, we stop here,
|
||||||
# otherwise we recursively grab roles and all of their deps.
|
# otherwise we recursively grab roles and all of their deps.
|
||||||
tmp_file = role.fetch(role_data)
|
tmp_file = role.fetch(role_data)
|
||||||
|
|
||||||
if tmp_file:
|
if tmp_file:
|
||||||
|
self.display.debug('using %s' % tmp_file)
|
||||||
installed = role.install(tmp_file)
|
installed = role.install(tmp_file)
|
||||||
# we're done with the temp file, clean it up
|
# we're done with the temp file, clean it up if we created it
|
||||||
if tmp_file != role.src:
|
if tmp_file != role.src:
|
||||||
os.unlink(tmp_file)
|
os.unlink(tmp_file)
|
||||||
|
|
||||||
# install dependencies, if we want them
|
# install dependencies, if we want them
|
||||||
if not no_deps and installed:
|
if not no_deps and installed:
|
||||||
role_dependencies = role.metadata.get('dependencies', [])
|
role_dependencies = role.metadata.get('dependencies', [])
|
||||||
|
@ -460,9 +404,10 @@ class GalaxyCLI(CLI):
|
||||||
else:
|
else:
|
||||||
self.display.display('- dependency %s is already installed, skipping.' % dep_name)
|
self.display.display('- dependency %s is already installed, skipping.' % dep_name)
|
||||||
|
|
||||||
if not tmp_file or not installed:
|
if not installed:
|
||||||
self.display.warning("- %s was NOT installed successfully." % role.name)
|
self.display.warning("- %s was NOT installed successfully." % role.name)
|
||||||
self.exit_without_ignore()
|
self.exit_without_ignore()
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def execute_remove(self):
|
def execute_remove(self):
|
||||||
|
|
|
@ -21,15 +21,16 @@
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import os
|
import os
|
||||||
import subprocess
|
|
||||||
import tarfile
|
import tarfile
|
||||||
import tempfile
|
import tempfile
|
||||||
import yaml
|
import yaml
|
||||||
|
from distutils.version import LooseVersion
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
|
|
||||||
from ansible import constants as C
|
|
||||||
from ansible.errors import AnsibleError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.module_utils.urls import open_url
|
from ansible.module_utils.urls import open_url
|
||||||
|
from ansible.playbook.role.requirement import RoleRequirement
|
||||||
|
from ansible.galaxy.api import GalaxyAPI
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from __main__ import display
|
from __main__ import display
|
||||||
|
@ -51,6 +52,7 @@ class GalaxyRole(object):
|
||||||
self._install_info = None
|
self._install_info = None
|
||||||
|
|
||||||
self.options = galaxy.options
|
self.options = galaxy.options
|
||||||
|
self.galaxy = galaxy
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
self.version = version
|
self.version = version
|
||||||
|
@ -135,9 +137,9 @@ class GalaxyRole(object):
|
||||||
|
|
||||||
def remove(self):
|
def remove(self):
|
||||||
"""
|
"""
|
||||||
Removes the specified role from the roles path. There is a
|
Removes the specified role from the roles path.
|
||||||
sanity check to make sure there's a meta/main.yml file at this
|
There is a sanity check to make sure there's a meta/main.yml file at this
|
||||||
path so the user doesn't blow away random directories
|
path so the user doesn't blow away random directories.
|
||||||
"""
|
"""
|
||||||
if self.metadata:
|
if self.metadata:
|
||||||
try:
|
try:
|
||||||
|
@ -159,6 +161,7 @@ class GalaxyRole(object):
|
||||||
archive_url = 'https://github.com/%s/%s/archive/%s.tar.gz' % (role_data["github_user"], role_data["github_repo"], self.version)
|
archive_url = 'https://github.com/%s/%s/archive/%s.tar.gz' % (role_data["github_user"], role_data["github_repo"], self.version)
|
||||||
else:
|
else:
|
||||||
archive_url = self.src
|
archive_url = self.src
|
||||||
|
|
||||||
display.display("- downloading role from %s" % archive_url)
|
display.display("- downloading role from %s" % archive_url)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -170,25 +173,64 @@ class GalaxyRole(object):
|
||||||
data = url_file.read()
|
data = url_file.read()
|
||||||
temp_file.close()
|
temp_file.close()
|
||||||
return temp_file.name
|
return temp_file.name
|
||||||
except:
|
except Exception as e:
|
||||||
# TODO: better urllib2 error handling for error
|
display.error("failed to download the file: %s" % str(e))
|
||||||
# messages that are more exact
|
|
||||||
display.error("failed to download the file.")
|
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def install(self, role_filename):
|
def install(self):
|
||||||
# the file is a tar, so open it that way and extract it
|
# the file is a tar, so open it that way and extract it
|
||||||
# to the specified (or default) roles directory
|
# to the specified (or default) roles directory
|
||||||
|
|
||||||
if not tarfile.is_tarfile(role_filename):
|
if self.scm:
|
||||||
display.error("the file downloaded was not a tar.gz")
|
# create tar file from scm url
|
||||||
return False
|
tmp_file = RoleRequirement.scm_archive_role(**self.spec)
|
||||||
|
elif self.src:
|
||||||
|
if os.path.isfile(self.src):
|
||||||
|
# installing a local tar.gz
|
||||||
|
tmp_file = self.src
|
||||||
|
elif '://' in self.src:
|
||||||
|
role_data = self.src
|
||||||
|
tmp_file = self.fetch(role_data)
|
||||||
else:
|
else:
|
||||||
if role_filename.endswith('.gz'):
|
api = GalaxyAPI(self.galaxy, self.options.api_server)
|
||||||
role_tar_file = tarfile.open(role_filename, "r:gz")
|
role_data = api.lookup_role_by_name(self.src)
|
||||||
|
if not role_data:
|
||||||
|
raise AnsibleError("- sorry, %s was not found on %s." % (self.src, self.options.api_server))
|
||||||
|
|
||||||
|
role_versions = api.fetch_role_related('versions', role_data['id'])
|
||||||
|
if not self.version:
|
||||||
|
# convert the version names to LooseVersion objects
|
||||||
|
# and sort them to get the latest version. If there
|
||||||
|
# are no versions in the list, we'll grab the head
|
||||||
|
# of the master branch
|
||||||
|
if len(role_versions) > 0:
|
||||||
|
loose_versions = [LooseVersion(a.get('name',None)) for a in role_versions]
|
||||||
|
loose_versions.sort()
|
||||||
|
self.version = str(loose_versions[-1])
|
||||||
else:
|
else:
|
||||||
role_tar_file = tarfile.open(role_filename, "r")
|
self.version = 'master'
|
||||||
|
elif self.version != 'master':
|
||||||
|
if role_versions and self.version not in [a.get('name', None) for a in role_versions]:
|
||||||
|
raise AnsibleError("- the specified version (%s) of %s was not found in the list of available versions (%s)." % (self.version, self.name, role_versions))
|
||||||
|
|
||||||
|
tmp_file = self.fetch(role_data)
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise AnsibleError("No valid role data found")
|
||||||
|
|
||||||
|
|
||||||
|
if tmp_file:
|
||||||
|
|
||||||
|
display.display("installing from %s" % tmp_file)
|
||||||
|
|
||||||
|
if not tarfile.is_tarfile(tmp_file):
|
||||||
|
raise AnsibleError("the file downloaded was not a tar.gz")
|
||||||
|
else:
|
||||||
|
if tmp_file.endswith('.gz'):
|
||||||
|
role_tar_file = tarfile.open(tmp_file, "r:gz")
|
||||||
|
else:
|
||||||
|
role_tar_file = tarfile.open(tmp_file, "r")
|
||||||
# verify the role's meta file
|
# verify the role's meta file
|
||||||
meta_file = None
|
meta_file = None
|
||||||
members = role_tar_file.getmembers()
|
members = role_tar_file.getmembers()
|
||||||
|
@ -198,14 +240,12 @@ class GalaxyRole(object):
|
||||||
meta_file = member
|
meta_file = member
|
||||||
break
|
break
|
||||||
if not meta_file:
|
if not meta_file:
|
||||||
display.error("this role does not appear to have a meta/main.yml file.")
|
raise AnsibleError("this role does not appear to have a meta/main.yml file.")
|
||||||
return False
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
self._metadata = yaml.safe_load(role_tar_file.extractfile(meta_file))
|
self._metadata = yaml.safe_load(role_tar_file.extractfile(meta_file))
|
||||||
except:
|
except:
|
||||||
display.error("this role does not appear to have a valid meta/main.yml file.")
|
raise AnsibleError("this role does not appear to have a valid meta/main.yml file.")
|
||||||
return False
|
|
||||||
|
|
||||||
# we strip off the top-level directory for all of the files contained within
|
# we strip off the top-level directory for all of the files contained within
|
||||||
# the tar file here, since the default is 'github_repo-target', and change it
|
# the tar file here, since the default is 'github_repo-target', and change it
|
||||||
|
@ -214,17 +254,13 @@ class GalaxyRole(object):
|
||||||
try:
|
try:
|
||||||
if os.path.exists(self.path):
|
if os.path.exists(self.path):
|
||||||
if not os.path.isdir(self.path):
|
if not os.path.isdir(self.path):
|
||||||
display.error("the specified roles path exists and is not a directory.")
|
raise AnsibleError("the specified roles path exists and is not a directory.")
|
||||||
return False
|
|
||||||
elif not getattr(self.options, "force", False):
|
elif not getattr(self.options, "force", False):
|
||||||
display.error("the specified role %s appears to already exist. Use --force to replace it." % self.name)
|
raise AnsibleError("the specified role %s appears to already exist. Use --force to replace it." % self.name)
|
||||||
return False
|
|
||||||
else:
|
else:
|
||||||
# using --force, remove the old path
|
# using --force, remove the old path
|
||||||
if not self.remove():
|
if not self.remove():
|
||||||
display.error("%s doesn't appear to contain a role." % self.path)
|
raise AnsibleError("%s doesn't appear to contain a role.\n please remove this directory manually if you really want to put the role here." % self.path)
|
||||||
display.error(" please remove this directory manually if you really want to put the role here.")
|
|
||||||
return False
|
|
||||||
else:
|
else:
|
||||||
os.makedirs(self.path)
|
os.makedirs(self.path)
|
||||||
|
|
||||||
|
@ -245,13 +281,18 @@ class GalaxyRole(object):
|
||||||
# write out the install info file for later use
|
# write out the install info file for later use
|
||||||
self._write_galaxy_install_info()
|
self._write_galaxy_install_info()
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
display.error("Could not update files in %s: %s" % (self.path, str(e)))
|
raise AnsibleError("Could not update files in %s: %s" % (self.path, str(e)))
|
||||||
return False
|
|
||||||
|
|
||||||
# return the parsed yaml metadata
|
# return the parsed yaml metadata
|
||||||
display.display("- %s was installed successfully" % self.name)
|
display.display("- %s was installed successfully" % self.name)
|
||||||
|
try:
|
||||||
|
os.unlink(tmp_file)
|
||||||
|
except (OSError,IOError) as e:
|
||||||
|
display.warning("Unable to remove tmp file (%s): %s" % (tmp_file, str(e)))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def spec(self):
|
def spec(self):
|
||||||
"""
|
"""
|
||||||
|
@ -266,65 +307,3 @@ class GalaxyRole(object):
|
||||||
return dict(scm=self.scm, src=self.src, version=self.version, name=self.name)
|
return dict(scm=self.scm, src=self.src, version=self.version, name=self.name)
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def url_to_spec(roleurl):
|
|
||||||
# gets the role name out of a repo like
|
|
||||||
# http://git.example.com/repos/repo.git" => "repo"
|
|
||||||
|
|
||||||
if '://' not in roleurl and '@' not in roleurl:
|
|
||||||
return roleurl
|
|
||||||
trailing_path = roleurl.split('/')[-1]
|
|
||||||
if trailing_path.endswith('.git'):
|
|
||||||
trailing_path = trailing_path[:-4]
|
|
||||||
if trailing_path.endswith('.tar.gz'):
|
|
||||||
trailing_path = trailing_path[:-7]
|
|
||||||
if ',' in trailing_path:
|
|
||||||
trailing_path = trailing_path.split(',')[0]
|
|
||||||
return trailing_path
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def scm_archive_role(scm, role_url, role_version, role_name):
|
|
||||||
if scm not in ['hg', 'git']:
|
|
||||||
display.display("- scm %s is not currently supported" % scm)
|
|
||||||
return False
|
|
||||||
tempdir = tempfile.mkdtemp()
|
|
||||||
clone_cmd = [scm, 'clone', role_url, role_name]
|
|
||||||
with open('/dev/null', 'w') as devnull:
|
|
||||||
try:
|
|
||||||
display.display("- executing: %s" % " ".join(clone_cmd))
|
|
||||||
popen = subprocess.Popen(clone_cmd, cwd=tempdir, stdout=devnull, stderr=devnull)
|
|
||||||
except:
|
|
||||||
raise AnsibleError("error executing: %s" % " ".join(clone_cmd))
|
|
||||||
rc = popen.wait()
|
|
||||||
if rc != 0:
|
|
||||||
display.display("- command %s failed" % ' '.join(clone_cmd))
|
|
||||||
display.display(" in directory %s" % tempdir)
|
|
||||||
return False
|
|
||||||
|
|
||||||
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.tar')
|
|
||||||
if scm == 'hg':
|
|
||||||
archive_cmd = ['hg', 'archive', '--prefix', "%s/" % role_name]
|
|
||||||
if role_version:
|
|
||||||
archive_cmd.extend(['-r', role_version])
|
|
||||||
archive_cmd.append(temp_file.name)
|
|
||||||
if scm == 'git':
|
|
||||||
archive_cmd = ['git', 'archive', '--prefix=%s/' % role_name, '--output=%s' % temp_file.name]
|
|
||||||
if role_version:
|
|
||||||
archive_cmd.append(role_version)
|
|
||||||
else:
|
|
||||||
archive_cmd.append('HEAD')
|
|
||||||
|
|
||||||
with open('/dev/null', 'w') as devnull:
|
|
||||||
display.display("- executing: %s" % " ".join(archive_cmd))
|
|
||||||
popen = subprocess.Popen(archive_cmd, cwd=os.path.join(tempdir, role_name),
|
|
||||||
stderr=devnull, stdout=devnull)
|
|
||||||
rc = popen.wait()
|
|
||||||
if rc != 0:
|
|
||||||
display.display("- command %s failed" % ' '.join(archive_cmd))
|
|
||||||
display.display(" in directory %s" % tempdir)
|
|
||||||
return False
|
|
||||||
|
|
||||||
rmtree(tempdir, ignore_errors=True)
|
|
||||||
|
|
||||||
return temp_file.name
|
|
||||||
|
|
||||||
|
|
|
@ -21,19 +21,14 @@ __metaclass__ = type
|
||||||
|
|
||||||
from six import iteritems, string_types
|
from six import iteritems, string_types
|
||||||
|
|
||||||
import inspect
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from hashlib import sha1
|
|
||||||
|
|
||||||
from ansible.errors import AnsibleError, AnsibleParserError
|
from ansible.errors import AnsibleError, AnsibleParserError
|
||||||
from ansible.parsing import DataLoader
|
|
||||||
from ansible.playbook.attribute import FieldAttribute
|
from ansible.playbook.attribute import FieldAttribute
|
||||||
from ansible.playbook.base import Base
|
from ansible.playbook.base import Base
|
||||||
from ansible.playbook.become import Become
|
from ansible.playbook.become import Become
|
||||||
from ansible.playbook.conditional import Conditional
|
from ansible.playbook.conditional import Conditional
|
||||||
from ansible.playbook.helpers import load_list_of_blocks
|
from ansible.playbook.helpers import load_list_of_blocks
|
||||||
from ansible.playbook.role.include import RoleInclude
|
|
||||||
from ansible.playbook.role.metadata import RoleMetadata
|
from ansible.playbook.role.metadata import RoleMetadata
|
||||||
from ansible.playbook.taggable import Taggable
|
from ansible.playbook.taggable import Taggable
|
||||||
from ansible.plugins import get_all_plugin_loaders
|
from ansible.plugins import get_all_plugin_loaders
|
||||||
|
|
|
@ -19,11 +19,14 @@
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
__metaclass__ = type
|
||||||
|
|
||||||
from six import iteritems, string_types
|
from six import string_types
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
|
||||||
from ansible.errors import AnsibleError, AnsibleParserError
|
from ansible.errors import AnsibleError
|
||||||
from ansible.playbook.role.definition import RoleDefinition
|
from ansible.playbook.role.definition import RoleDefinition
|
||||||
|
|
||||||
__all__ = ['RoleRequirement']
|
__all__ = ['RoleRequirement']
|
||||||
|
@ -73,7 +76,7 @@ class RoleRequirement(RoleDefinition):
|
||||||
def _preprocess_role_spec(self, ds):
|
def _preprocess_role_spec(self, ds):
|
||||||
if 'role' in ds:
|
if 'role' in ds:
|
||||||
# Old style: {role: "galaxy.role,version,name", other_vars: "here" }
|
# Old style: {role: "galaxy.role,version,name", other_vars: "here" }
|
||||||
role_info = role_spec_parse(ds['role'])
|
role_info = RoleRequirement.role_spec_parse(ds['role'])
|
||||||
if isinstance(role_info, dict):
|
if isinstance(role_info, dict):
|
||||||
# Warning: Slight change in behaviour here. name may be being
|
# Warning: Slight change in behaviour here. name may be being
|
||||||
# overloaded. Previously, name was only a parameter to the role.
|
# overloaded. Previously, name was only a parameter to the role.
|
||||||
|
@ -96,7 +99,7 @@ class RoleRequirement(RoleDefinition):
|
||||||
ds["role"] = ds["name"]
|
ds["role"] = ds["name"]
|
||||||
del ds["name"]
|
del ds["name"]
|
||||||
else:
|
else:
|
||||||
ds["role"] = repo_url_to_role_name(ds["src"])
|
ds["role"] = RoleRequirement.repo_url_to_role_name(ds["src"])
|
||||||
|
|
||||||
# set some values to a default value, if none were specified
|
# set some values to a default value, if none were specified
|
||||||
ds.setdefault('version', '')
|
ds.setdefault('version', '')
|
||||||
|
@ -104,7 +107,8 @@ class RoleRequirement(RoleDefinition):
|
||||||
|
|
||||||
return ds
|
return ds
|
||||||
|
|
||||||
def repo_url_to_role_name(repo_url):
|
@staticmethod
|
||||||
|
def repo_url_to_role_name(repo_url):
|
||||||
# gets the role name out of a repo like
|
# gets the role name out of a repo like
|
||||||
# http://git.example.com/repos/repo.git" => "repo"
|
# http://git.example.com/repos/repo.git" => "repo"
|
||||||
|
|
||||||
|
@ -119,7 +123,8 @@ def repo_url_to_role_name(repo_url):
|
||||||
trailing_path = trailing_path.split(',')[0]
|
trailing_path = trailing_path.split(',')[0]
|
||||||
return trailing_path
|
return trailing_path
|
||||||
|
|
||||||
def role_spec_parse(role_spec):
|
@staticmethod
|
||||||
|
def role_spec_parse(role_spec):
|
||||||
# takes a repo and a version like
|
# takes a repo and a version like
|
||||||
# git+http://git.example.com/repos/repo.git,v1.0
|
# git+http://git.example.com/repos/repo.git,v1.0
|
||||||
# and returns a list of properties such as:
|
# and returns a list of properties such as:
|
||||||
|
@ -156,50 +161,83 @@ def role_spec_parse(role_spec):
|
||||||
if len(tokens) == 3:
|
if len(tokens) == 3:
|
||||||
role_name = tokens[2]
|
role_name = tokens[2]
|
||||||
else:
|
else:
|
||||||
role_name = repo_url_to_role_name(tokens[0])
|
role_name = RoleRequirement.repo_url_to_role_name(tokens[0])
|
||||||
|
|
||||||
if scm and not role_version:
|
if scm and not role_version:
|
||||||
role_version = default_role_versions.get(scm, '')
|
role_version = default_role_versions.get(scm, '')
|
||||||
|
|
||||||
return dict(scm=scm, src=role_url, version=role_version, role_name=role_name)
|
return dict(scm=scm, src=role_url, version=role_version, name=role_name)
|
||||||
|
|
||||||
# FIXME: all of these methods need to be cleaned up/reorganized below this
|
@staticmethod
|
||||||
def get_opt(options, k, defval=""):
|
def role_yaml_parse(role):
|
||||||
"""
|
|
||||||
Returns an option from an Optparse values instance.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
data = getattr(options, k)
|
|
||||||
except:
|
|
||||||
return defval
|
|
||||||
if k == "roles_path":
|
|
||||||
if os.pathsep in data:
|
|
||||||
data = data.split(os.pathsep)[0]
|
|
||||||
return data
|
|
||||||
|
|
||||||
def get_role_path(role_name, options):
|
if 'role' in role:
|
||||||
"""
|
# Old style: {role: "galaxy.role,version,name", other_vars: "here" }
|
||||||
Returns the role path based on the roles_path option
|
role_info = RoleRequirement.role_spec_parse(role['role'])
|
||||||
and the role name.
|
if isinstance(role_info, dict):
|
||||||
"""
|
# Warning: Slight change in behaviour here. name may be being
|
||||||
roles_path = get_opt(options,'roles_path')
|
# overloaded. Previously, name was only a parameter to the role.
|
||||||
roles_path = os.path.join(roles_path, role_name)
|
# Now it is both a parameter to the role and the name that
|
||||||
roles_path = os.path.expanduser(roles_path)
|
# ansible-galaxy will install under on the local system.
|
||||||
return roles_path
|
if 'name' in role and 'name' in role_info:
|
||||||
|
del role_info['name']
|
||||||
def get_role_metadata(role_name, options):
|
role.update(role_info)
|
||||||
"""
|
|
||||||
Returns the metadata as YAML, if the file 'meta/main.yml'
|
|
||||||
exists in the specified role_path
|
|
||||||
"""
|
|
||||||
role_path = os.path.join(get_role_path(role_name, options), 'meta/main.yml')
|
|
||||||
try:
|
|
||||||
if os.path.isfile(role_path):
|
|
||||||
f = open(role_path, 'r')
|
|
||||||
meta_data = yaml.safe_load(f)
|
|
||||||
f.close()
|
|
||||||
return meta_data
|
|
||||||
else:
|
else:
|
||||||
return None
|
# New style: { src: 'galaxy.role,version,name', other_vars: "here" }
|
||||||
|
if 'github.com' in role["src"] and 'http' in role["src"] and '+' not in role["src"] and not role["src"].endswith('.tar.gz'):
|
||||||
|
role["src"] = "git+" + role["src"]
|
||||||
|
|
||||||
|
if '+' in role["src"]:
|
||||||
|
(scm, src) = role["src"].split('+')
|
||||||
|
role["scm"] = scm
|
||||||
|
role["src"] = src
|
||||||
|
|
||||||
|
if 'name' not in role:
|
||||||
|
role["name"] = RoleRequirement.repo_url_to_role_name(role["src"])
|
||||||
|
|
||||||
|
if 'version' not in role:
|
||||||
|
role['version'] = ''
|
||||||
|
|
||||||
|
if 'scm' not in role:
|
||||||
|
role['scm'] = None
|
||||||
|
|
||||||
|
return role
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def scm_archive_role(src, scm='git', name=None, version='HEAD'):
|
||||||
|
if scm not in ['hg', 'git']:
|
||||||
|
raise AnsibleError("- scm %s is not currently supported" % scm)
|
||||||
|
tempdir = tempfile.mkdtemp()
|
||||||
|
clone_cmd = [scm, 'clone', src, name]
|
||||||
|
with open('/dev/null', 'w') as devnull:
|
||||||
|
try:
|
||||||
|
popen = subprocess.Popen(clone_cmd, cwd=tempdir, stdout=devnull, stderr=devnull)
|
||||||
except:
|
except:
|
||||||
return None
|
raise AnsibleError("error executing: %s" % " ".join(clone_cmd))
|
||||||
|
rc = popen.wait()
|
||||||
|
if rc != 0:
|
||||||
|
raise AnsibleError ("- command %s failed in directory %s" % (' '.join(clone_cmd), tempdir))
|
||||||
|
|
||||||
|
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.tar')
|
||||||
|
if scm == 'hg':
|
||||||
|
archive_cmd = ['hg', 'archive', '--prefix', "%s/" % name]
|
||||||
|
if version:
|
||||||
|
archive_cmd.extend(['-r', version])
|
||||||
|
archive_cmd.append(temp_file.name)
|
||||||
|
if scm == 'git':
|
||||||
|
archive_cmd = ['git', 'archive', '--prefix=%s/' % name, '--output=%s' % temp_file.name]
|
||||||
|
if version:
|
||||||
|
archive_cmd.append(version)
|
||||||
|
else:
|
||||||
|
archive_cmd.append('HEAD')
|
||||||
|
|
||||||
|
with open('/dev/null', 'w') as devnull:
|
||||||
|
popen = subprocess.Popen(archive_cmd, cwd=os.path.join(tempdir, name),
|
||||||
|
stderr=devnull, stdout=devnull)
|
||||||
|
rc = popen.wait()
|
||||||
|
if rc != 0:
|
||||||
|
raise AnsibleError("- command %s failed in directory %s" % (' '.join(archive_cmd), tempdir))
|
||||||
|
|
||||||
|
shutil.rmtree(tempdir, ignore_errors=True)
|
||||||
|
return temp_file.name
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@ def get_docstring(filename, verbose=False):
|
||||||
theid = t.id
|
theid = t.id
|
||||||
except AttributeError as e:
|
except AttributeError as e:
|
||||||
# skip errors can happen when trying to use the normal code
|
# skip errors can happen when trying to use the normal code
|
||||||
|
display.warning("Failed to assign id for %t on %s, skipping" % (t, filename))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if 'DOCUMENTATION' in theid:
|
if 'DOCUMENTATION' in theid:
|
||||||
|
@ -119,6 +120,7 @@ def get_docstring(filename, verbose=False):
|
||||||
except:
|
except:
|
||||||
display.error("unable to parse %s" % filename)
|
display.error("unable to parse %s" % filename)
|
||||||
if verbose == True:
|
if verbose == True:
|
||||||
|
display.display("unable to parse %s" % filename)
|
||||||
raise
|
raise
|
||||||
return doc, plainexamples, returndocs
|
return doc, plainexamples, returndocs
|
||||||
|
|
||||||
|
|
|
@ -172,7 +172,7 @@ test_galaxy: test_galaxy_spec test_galaxy_yaml
|
||||||
|
|
||||||
test_galaxy_spec:
|
test_galaxy_spec:
|
||||||
mytmpdir=$(MYTMPDIR) ; \
|
mytmpdir=$(MYTMPDIR) ; \
|
||||||
ansible-galaxy install -r galaxy_rolesfile -p $$mytmpdir/roles ; \
|
ansible-galaxy install -r galaxy_rolesfile -p $$mytmpdir/roles -vvvv ; \
|
||||||
cp galaxy_playbook.yml $$mytmpdir ; \
|
cp galaxy_playbook.yml $$mytmpdir ; \
|
||||||
ansible-playbook -i $(INVENTORY) $$mytmpdir/galaxy_playbook.yml -v $(TEST_FLAGS) ; \
|
ansible-playbook -i $(INVENTORY) $$mytmpdir/galaxy_playbook.yml -v $(TEST_FLAGS) ; \
|
||||||
RC=$$? ; \
|
RC=$$? ; \
|
||||||
|
@ -181,7 +181,7 @@ test_galaxy_spec:
|
||||||
|
|
||||||
test_galaxy_yaml:
|
test_galaxy_yaml:
|
||||||
mytmpdir=$(MYTMPDIR) ; \
|
mytmpdir=$(MYTMPDIR) ; \
|
||||||
ansible-galaxy install -r galaxy_roles.yml -p $$mytmpdir/roles ; \
|
ansible-galaxy install -r galaxy_roles.yml -p $$mytmpdir/roles -vvvv; \
|
||||||
cp galaxy_playbook.yml $$mytmpdir ; \
|
cp galaxy_playbook.yml $$mytmpdir ; \
|
||||||
ansible-playbook -i $(INVENTORY) $$mytmpdir/galaxy_playbook.yml -v $(TEST_FLAGS) ; \
|
ansible-playbook -i $(INVENTORY) $$mytmpdir/galaxy_playbook.yml -v $(TEST_FLAGS) ; \
|
||||||
RC=$$? ; \
|
RC=$$? ; \
|
||||||
|
|
Loading…
Reference in a new issue