Allow installation of roles from yaml roles file
Added docs Added more tests Improved how roles are returned from the parsers
This commit is contained in:
parent
46b59b02ed
commit
ada9074276
7 changed files with 71 additions and 28 deletions
|
@ -696,10 +696,12 @@ def execute_install(args, options, parser):
|
||||||
|
|
||||||
roles_done = []
|
roles_done = []
|
||||||
if role_file:
|
if role_file:
|
||||||
# roles listed in a file, one per line
|
|
||||||
# so we'll go through and grab them all
|
|
||||||
f = open(role_file, 'r')
|
f = open(role_file, 'r')
|
||||||
roles_left = f.readlines()
|
if role_file.endswith('.yaml') or role_file.endswith('.yml'):
|
||||||
|
roles_left = map(ansible.utils.role_yaml_parse, yaml.safe_load(f))
|
||||||
|
else:
|
||||||
|
# roles listed in a file, one per line
|
||||||
|
roles_left = map(ansible.utils.role_spec_parse, f.readlines())
|
||||||
f.close()
|
f.close()
|
||||||
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
|
||||||
|
@ -708,16 +710,18 @@ def execute_install(args, options, parser):
|
||||||
|
|
||||||
while len(roles_left) > 0:
|
while len(roles_left) > 0:
|
||||||
# query the galaxy API for the role data
|
# query the galaxy API for the role data
|
||||||
(scm, role_src, role_version, role_name) = ansible.utils.role_spec_parse(roles_left.pop(0))
|
|
||||||
role_data = None
|
role_data = None
|
||||||
|
role = roles_left.pop(0)
|
||||||
|
role_src = role.get("src")
|
||||||
|
role_scm = role.get("scm")
|
||||||
|
|
||||||
if os.path.isfile(role_src):
|
if os.path.isfile(role_src):
|
||||||
# installing a local tar.gz
|
# installing a local tar.gz
|
||||||
tmp_file = role_src
|
tmp_file = role_src
|
||||||
else:
|
else:
|
||||||
if scm:
|
if role_scm:
|
||||||
# create tar file from scm url
|
# create tar file from scm url
|
||||||
tmp_file = scm_archive_role(scm, role_src, role_version, role_name)
|
tmp_file = scm_archive_role(role_scm, role_src, role.get("version"), role.get("name"))
|
||||||
elif '://' in role_src:
|
elif '://' in role_src:
|
||||||
# just download a URL - version will probably be in the URL
|
# just download a URL - version will probably be in the URL
|
||||||
tmp_file = fetch_role(role_src, None, None, options)
|
tmp_file = fetch_role(role_src, None, None, options)
|
||||||
|
@ -729,7 +733,7 @@ def execute_install(args, options, parser):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
role_versions = api_fetch_role_related(api_server, 'versions', role_data['id'])
|
role_versions = api_fetch_role_related(api_server, 'versions', role_data['id'])
|
||||||
if not role_version:
|
if "version" not in role:
|
||||||
# convert the version names to LooseVersion objects
|
# convert the version names to LooseVersion objects
|
||||||
# and sort them to get the latest version. If there
|
# and sort them to get the latest version. If there
|
||||||
# are no versions in the list, we'll grab the head
|
# are no versions in the list, we'll grab the head
|
||||||
|
@ -737,40 +741,43 @@ def execute_install(args, options, parser):
|
||||||
if len(role_versions) > 0:
|
if len(role_versions) > 0:
|
||||||
loose_versions = [LooseVersion(a.get('name',None)) for a in role_versions]
|
loose_versions = [LooseVersion(a.get('name',None)) for a in role_versions]
|
||||||
loose_versions.sort()
|
loose_versions.sort()
|
||||||
role_version = str(loose_versions[-1])
|
role["version"] = str(loose_versions[-1])
|
||||||
else:
|
else:
|
||||||
role_version = 'master'
|
role["version"] = 'master'
|
||||||
print " no version specified, installing %s" % role_version
|
print " no version specified, installing %s" % role.version
|
||||||
else:
|
else:
|
||||||
if role_versions and role_version not in [a.get('name',None) for a in role_versions]:
|
if role_versions and role["version"] not in [a.get('name',None) for a in role_versions]:
|
||||||
print "The specified version (%s) was not found in the list of available versions." % role_version
|
print "The specified version (%s) was not found in the list of available versions." % role.version
|
||||||
exit_without_ignore(options)
|
exit_without_ignore(options)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 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 = fetch_role(role_src, role_version, role_data, options)
|
tmp_file = fetch_role(role_src, role["version"], role_data, options)
|
||||||
if tmp_file and install_role(role_name, role_version, tmp_file, options):
|
if tmp_file and install_role(role.get("name"), role.get("version"), tmp_file, options):
|
||||||
# we're done with the temp file, clean it up
|
# we're done with the temp file, clean it up
|
||||||
os.unlink(tmp_file)
|
os.unlink(tmp_file)
|
||||||
# install dependencies, if we want them
|
# install dependencies, if we want them
|
||||||
if not no_deps:
|
if not no_deps:
|
||||||
if not role_data:
|
if not role_data:
|
||||||
role_data = get_role_metadata(role_name, options)
|
role_data = get_role_metadata(role.get("name"), options)
|
||||||
role_dependencies = role_data['dependencies']
|
role_dependencies = role_data['dependencies']
|
||||||
else:
|
else:
|
||||||
role_dependencies = role_data['summary_fields']['dependencies'] # api_fetch_role_related(api_server, 'dependencies', role_data['id'])
|
role_dependencies = role_data['summary_fields']['dependencies'] # api_fetch_role_related(api_server, 'dependencies', role_data['id'])
|
||||||
for dep_name in role_dependencies:
|
for dep in role_dependencies:
|
||||||
#dep_name = "%s.%s" % (dep['owner'], dep['name'])
|
if isinstance(dep, str):
|
||||||
if not get_role_metadata(dep_name.split('/')[-1], options):
|
dep = ansible.utils.role_spec_parse(dep)
|
||||||
print ' adding dependency: %s' % dep_name
|
|
||||||
roles_left.append(dep_name)
|
|
||||||
else:
|
else:
|
||||||
print ' dependency %s is already installed, skipping.' % dep_name
|
dep = ansible.utils.role_yaml_parse(dep)
|
||||||
|
if not get_role_metadata(dep["name"], options):
|
||||||
|
print ' adding dependency: %s' % dep["name"]
|
||||||
|
roles_left.append(dep)
|
||||||
|
else:
|
||||||
|
print ' dependency %s is already installed, skipping.' % dep["name"]
|
||||||
else:
|
else:
|
||||||
if tmp_file:
|
if tmp_file:
|
||||||
os.unlink(tmp_file)
|
os.unlink(tmp_file)
|
||||||
print "%s was NOT installed successfully." % role_name
|
print "%s was NOT installed successfully." % role.get("name")
|
||||||
exit_without_ignore(options)
|
exit_without_ignore(options)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
|
@ -299,6 +299,13 @@ Role dependencies can also be specified as a full path, just like top level role
|
||||||
dependencies:
|
dependencies:
|
||||||
- { role: '/path/to/common/roles/foo', x: 1 }
|
- { role: '/path/to/common/roles/foo', x: 1 }
|
||||||
|
|
||||||
|
Role dependencies can also be installed from source control repos or tar files, using a comma separated format of path, an optional version (tag, commit, branch etc) and optional friendly role name (an attempt is made to derive a role name from the repo name or archive filename)::
|
||||||
|
|
||||||
|
---
|
||||||
|
dependencies:
|
||||||
|
- { role: 'git+http://git.example.com/repos/role-foo,v1.1,foo' }
|
||||||
|
- { role: '/path/to/tar/file.tgz,,friendly-name' }
|
||||||
|
|
||||||
Roles dependencies are always executed before the role that includes them, and are recursive. By default,
|
Roles dependencies are always executed before the role that includes them, and are recursive. By default,
|
||||||
roles can also only be added as a dependency once - if another role also lists it as a dependency it will
|
roles can also only be added as a dependency once - if another role also lists it as a dependency it will
|
||||||
not be run again. This behavior can be overridden by adding `allow_duplicates: yes` to the `meta/main.yml` file.
|
not be run again. This behavior can be overridden by adding `allow_duplicates: yes` to the `meta/main.yml` file.
|
||||||
|
|
|
@ -187,7 +187,7 @@ class Play(object):
|
||||||
raise errors.AnsibleError("expected a role name in dictionary: %s" % orig_path)
|
raise errors.AnsibleError("expected a role name in dictionary: %s" % orig_path)
|
||||||
role_vars = orig_path
|
role_vars = orig_path
|
||||||
else:
|
else:
|
||||||
(scm, role_src, role_version, role_name) = utils.role_spec_parse(orig_path)
|
role_name = utils.role_spec_parse(orig_path)["name"]
|
||||||
|
|
||||||
role_path = None
|
role_path = None
|
||||||
|
|
||||||
|
@ -412,8 +412,7 @@ class Play(object):
|
||||||
if isinstance(role, dict):
|
if isinstance(role, dict):
|
||||||
role_name = role['role']
|
role_name = role['role']
|
||||||
else:
|
else:
|
||||||
role_name = role
|
role_name = utils.role_spec_parse(role)["name"]
|
||||||
(scm, role_src, role_version, role_name) = utils.role_spec_parse(role_name)
|
|
||||||
|
|
||||||
role_names.append(role_name)
|
role_names.append(role_name)
|
||||||
if os.path.isfile(task):
|
if os.path.isfile(task):
|
||||||
|
|
|
@ -380,7 +380,17 @@ def role_spec_parse(role_spec):
|
||||||
role_name = tokens[2]
|
role_name = tokens[2]
|
||||||
else:
|
else:
|
||||||
role_name = repo_url_to_role_name(tokens[0])
|
role_name = repo_url_to_role_name(tokens[0])
|
||||||
return (scm, role_url, role_version, role_name)
|
return dict(scm=scm, src=role_url, version=role_version, name=role_name)
|
||||||
|
|
||||||
|
|
||||||
|
def role_yaml_parse(role):
|
||||||
|
if '+' in role["src"]:
|
||||||
|
(scm, src) = role["src"].split('+')
|
||||||
|
role["scm"] = scm
|
||||||
|
role["src"] = src
|
||||||
|
if 'name' not in role:
|
||||||
|
role["name"] = repo_url_to_role_name(role["src"])
|
||||||
|
return role
|
||||||
|
|
||||||
|
|
||||||
def json_loads(data):
|
def json_loads(data):
|
||||||
|
|
|
@ -105,7 +105,9 @@ rackspace: $(CREDENTIALS_FILE)
|
||||||
CLOUD_RESOURCE_PREFIX="$(CLOUD_RESOURCE_PREFIX)" make rackspace_cleanup ; \
|
CLOUD_RESOURCE_PREFIX="$(CLOUD_RESOURCE_PREFIX)" make rackspace_cleanup ; \
|
||||||
exit $$RC;
|
exit $$RC;
|
||||||
|
|
||||||
test_galaxy:
|
test_galaxy: test_galaxy_spec test_galaxy_yaml
|
||||||
|
|
||||||
|
test_galaxy_spec:
|
||||||
mytmpdir=$(TMPDIR) ; \
|
mytmpdir=$(TMPDIR) ; \
|
||||||
ansible-galaxy install -r galaxy_rolesfile -p $$mytmpdir/roles ; \
|
ansible-galaxy install -r galaxy_rolesfile -p $$mytmpdir/roles ; \
|
||||||
cp galaxy_playbook.yml $$mytmpdir ; \
|
cp galaxy_playbook.yml $$mytmpdir ; \
|
||||||
|
@ -113,3 +115,12 @@ test_galaxy:
|
||||||
RC=$$? ; \
|
RC=$$? ; \
|
||||||
rm -rf $$mytmpdir ; \
|
rm -rf $$mytmpdir ; \
|
||||||
exit $$RC
|
exit $$RC
|
||||||
|
|
||||||
|
test_galaxy_yaml:
|
||||||
|
mytmpdir=$(TMPDIR) ; \
|
||||||
|
ansible-galaxy install -r galaxy_roles.yml -p $$mytmpdir/roles ; \
|
||||||
|
cp galaxy_playbook.yml $$mytmpdir ; \
|
||||||
|
ansible-playbook -i $(INVENTORY) $$mytmpdir/galaxy_playbook.yml -v $(TEST_FLAGS) ; \
|
||||||
|
RC=$$? ; \
|
||||||
|
rm -rf $$mytmpdir ; \
|
||||||
|
exit $$RC
|
||||||
|
|
|
@ -4,3 +4,4 @@
|
||||||
roles:
|
roles:
|
||||||
- "git-ansible-galaxy"
|
- "git-ansible-galaxy"
|
||||||
- "http-role"
|
- "http-role"
|
||||||
|
- "hg-ansible-galaxy"
|
||||||
|
|
8
test/integration/galaxy_roles.yml
Normal file
8
test/integration/galaxy_roles.yml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
- src: git+http://bitbucket.org/willthames/git-ansible-galaxy
|
||||||
|
version: v1.4
|
||||||
|
|
||||||
|
- src: ssh://hg@bitbucket.org/willthames/hg-ansible-galaxy
|
||||||
|
scm: hg
|
||||||
|
|
||||||
|
- src: https://bitbucket.org/willthames/http-ansible-galaxy/get/master.tar.gz
|
||||||
|
name: http-role
|
Loading…
Reference in a new issue