Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
ansible
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
ansible
Commits
97c2b2ec
Commit
97c2b2ec
authored
Oct 05, 2015
by
James Cammarata
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #12636 from bcoca/galaxy
Galaxy
parents
a3ed9fc1
6f88f79d
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
312 additions
and
380 deletions
+312
-380
lib/ansible/cli/__init__.py
+13
-0
lib/ansible/cli/galaxy.py
+40
-135
lib/ansible/galaxy/role.py
+116
-137
lib/ansible/playbook/role/__init__.py
+0
-5
lib/ansible/playbook/role/requirement.py
+139
-101
lib/ansible/utils/module_docs.py
+2
-0
test/integration/Makefile
+2
-2
No files found.
lib/ansible/cli/__init__.py
View file @
97c2b2ec
...
@@ -512,3 +512,16 @@ class CLI(object):
...
@@ -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
lib/ansible/cli/galaxy.py
View file @
97c2b2ec
...
@@ -29,8 +29,6 @@ from distutils.version import LooseVersion
...
@@ -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):
...
@@ -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):
...
@@ -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
=
"
\n
Role:
%
s
\n
"
%
role_info
[
'name'
]
text
=
"
\n
Role:
%
s
\n
"
%
role_info
[
'name'
]
...
@@ -298,9 +249,8 @@ class GalaxyCLI(CLI):
...
@@ -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,118 +301,73 @@ class GalaxyCLI(CLI):
...
@@ -351,118 +301,73 @@ 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
:
raise
AnsibleError
(
"Must specify name or src for role"
)
roles_left
.
append
(
GalaxyRole
(
self
.
galaxy
,
**
role
))
else
:
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
:
try
:
self
.
options
.
roles_path
=
role_path
installed
=
role
.
install
()
e
ls
e
:
e
xcept
AnsibleError
as
e
:
self
.
options
.
roles_path
=
roles_path
self
.
display
.
warning
(
"-
%
s was NOT installed successfully:
%
s "
%
(
role
.
name
,
str
(
e
)))
self
.
exit_without_ignore
()
self
.
display
.
debug
(
'Installing role
%
s from
%
s'
%
(
role
.
name
,
self
.
options
.
roles_path
))
continue
tmp_file
=
None
# install dependencies, if we want them
installed
=
False
if
not
no_deps
and
installed
:
if
role
.
src
and
os
.
path
.
isfile
(
role
.
src
):
role_dependencies
=
role
.
metadata
.
get
(
'dependencies'
,
[])
# installing a local tar.gz
for
dep
in
role_dependencies
:
tmp_file
=
role
.
src
self
.
display
.
debug
(
'Installing dep
%
s'
%
dep
)
else
:
dep_req
=
RoleRequirement
()
if
role
.
scm
:
__
,
dep_name
,
__
=
dep_req
.
parse
(
dep
)
# create tar file from scm url
dep_role
=
GalaxyRole
(
self
.
galaxy
,
name
=
dep_name
)
tmp_file
=
GalaxyRole
.
scm_archive_role
(
role
.
scm
,
role
.
src
,
role
.
version
,
role
.
name
)
if
dep_role
.
install_info
is
None
or
force
:
if
role
.
src
:
if
dep_role
not
in
roles_left
:
if
'://'
not
in
role
.
src
:
self
.
display
.
display
(
'- adding dependency:
%
s'
%
dep_name
)
role_data
=
self
.
api
.
lookup_role_by_name
(
role
.
src
)
roles_left
.
append
(
GalaxyRole
(
self
.
galaxy
,
name
=
dep_name
))
if
not
role_data
:
self
.
display
.
warning
(
"- sorry,
%
s was not found on
%
s."
%
(
role
.
src
,
self
.
options
.
api_server
))
self
.
exit_without_ignore
()
continue
role_versions
=
self
.
api
.
fetch_role_related
(
'versions'
,
role_data
[
'id'
])
if
not
role
.
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
()
role
.
version
=
str
(
loose_versions
[
-
1
])
else
:
role
.
version
=
'master'
elif
role
.
version
!=
'master'
:
if
role_versions
and
role
.
version
not
in
[
a
.
get
(
'name'
,
None
)
for
a
in
role_versions
]:
self
.
display
.
warning
(
'role is
%
s'
%
role
)
self
.
display
.
warning
(
"- the specified version (
%
s) was not found in the list of available versions (
%
s)."
%
(
role
.
version
,
role_versions
))
self
.
exit_without_ignore
()
continue
# download the role. if --no-deps was specified, we stop here,
# otherwise we recursively grab roles and all of their deps.
tmp_file
=
role
.
fetch
(
role_data
)
if
tmp_file
:
installed
=
role
.
install
(
tmp_file
)
# we're done with the temp file, clean it up
if
tmp_file
!=
role
.
src
:
os
.
unlink
(
tmp_file
)
# install dependencies, if we want them
if
not
no_deps
and
installed
:
role_dependencies
=
role
.
metadata
.
get
(
'dependencies'
,
[])
for
dep
in
role_dependencies
:
self
.
display
.
debug
(
'Installing dep
%
s'
%
dep
)
dep_req
=
RoleRequirement
()
__
,
dep_name
,
__
=
dep_req
.
parse
(
dep
)
dep_role
=
GalaxyRole
(
self
.
galaxy
,
name
=
dep_name
)
if
dep_role
.
install_info
is
None
or
force
:
if
dep_role
not
in
roles_left
:
self
.
display
.
display
(
'- adding dependency:
%
s'
%
dep_name
)
roles_left
.
append
(
GalaxyRole
(
self
.
galaxy
,
name
=
dep_name
))
else
:
self
.
display
.
display
(
'- dependency
%
s already pending installation.'
%
dep_name
)
else
:
else
:
self
.
display
.
display
(
'- dependency
%
s is already installed, skipping.'
%
dep_name
)
self
.
display
.
display
(
'- dependency
%
s already pending installation.'
%
dep_name
)
else
:
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
):
...
...
lib/ansible/galaxy/role.py
View file @
97c2b2ec
...
@@ -21,15 +21,16 @@
...
@@ -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):
...
@@ -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):
...
@@ -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):
...
@@ -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,87 +173,125 @@ class GalaxyRole(object):
...
@@ -170,87 +173,125 @@ 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
)
else
:
elif
self
.
src
:
if
role_filename
.
endswith
(
'.gz'
):
if
os
.
path
.
isfile
(
self
.
src
):
role_tar_file
=
tarfile
.
open
(
role_filename
,
"r:gz"
)
# 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
:
role_tar_file
=
tarfile
.
open
(
role_filename
,
"r"
)
api
=
GalaxyAPI
(
self
.
galaxy
,
self
.
options
.
api_server
)
# verify the role's meta file
role_data
=
api
.
lookup_role_by_name
(
self
.
src
)
meta_file
=
None
if
not
role_data
:
members
=
role_tar_file
.
getmembers
()
raise
AnsibleError
(
"- sorry,
%
s was not found on
%
s."
%
(
self
.
src
,
self
.
options
.
api_server
))
# next find the metadata file
for
member
in
members
:
role_versions
=
api
.
fetch_role_related
(
'versions'
,
role_data
[
'id'
])
if
self
.
META_MAIN
in
member
.
name
:
if
not
self
.
version
:
meta_file
=
member
# convert the version names to LooseVersion objects
break
# and sort them to get the latest version. If there
if
not
meta_file
:
# are no versions in the list, we'll grab the head
display
.
error
(
"this role does not appear to have a meta/main.yml file."
)
# of the master branch
return
False
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
:
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
:
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
meta_file
=
None
members
=
role_tar_file
.
getmembers
()
# next find the metadata file
for
member
in
members
:
if
self
.
META_MAIN
in
member
.
name
:
meta_file
=
member
break
if
not
meta_file
:
raise
AnsibleError
(
"this role does not appear to have a meta/main.yml file."
)
else
:
try
:
self
.
_metadata
=
yaml
.
safe_load
(
role_tar_file
.
extractfile
(
meta_file
))
except
:
raise
AnsibleError
(
"this role does not appear to have a valid meta/main.yml file."
)
# 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
# to the specified role's name
display
.
display
(
"- extracting
%
s to
%
s"
%
(
self
.
name
,
self
.
path
))
try
:
try
:
self
.
_metadata
=
yaml
.
safe_load
(
role_tar_file
.
extractfile
(
meta_file
))
if
os
.
path
.
exists
(
self
.
path
):
except
:
if
not
os
.
path
.
isdir
(
self
.
path
):
display
.
error
(
"this role does not appear to have a valid meta/main.yml file."
)
raise
AnsibleError
(
"the specified roles path exists and is not a directory."
)
return
False
elif
not
getattr
(
self
.
options
,
"force"
,
False
):
raise
AnsibleError
(
"the specified role
%
s appears to already exist. Use --force to replace it."
%
self
.
name
)
# we strip off the top-level directory for all of the files contained within
else
:
# the tar file here, since the default is 'github_repo-target', and change it
# using --force, remove the old path
# to the specified role's name
if
not
self
.
remove
():
display
.
display
(
"- extracting
%
s to
%
s"
%
(
self
.
name
,
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
)
try
:
if
os
.
path
.
exists
(
self
.
path
):
if
not
os
.
path
.
isdir
(
self
.
path
):
display
.
error
(
"the specified roles path exists and is not a directory."
)
return
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
)
return
False
else
:
else
:
# using --force, remove the old path
os
.
makedirs
(
self
.
path
)
if
not
self
.
remove
():
display
.
error
(
"
%
s doesn't appear to contain a role."
%
self
.
path
)
# now we do the actual extraction to the path
display
.
error
(
" please remove this directory manually if you really want to put the role here."
)
for
member
in
members
:
return
False
# we only extract files, and remove any relative path
else
:
# bits that might be in the file for security purposes
os
.
makedirs
(
self
.
path
)
# and drop the leading directory, as mentioned above
if
member
.
isreg
()
or
member
.
issym
():
parts
=
member
.
name
.
split
(
os
.
sep
)[
1
:]
final_parts
=
[]
for
part
in
parts
:
if
part
!=
'..'
and
'~'
not
in
part
and
'$'
not
in
part
:
final_parts
.
append
(
part
)
member
.
name
=
os
.
path
.
join
(
*
final_parts
)
role_tar_file
.
extract
(
member
,
self
.
path
)
# write out the install info file for later use
self
.
_write_galaxy_install_info
()
except
OSError
as
e
:
raise
AnsibleError
(
"Could not update files in
%
s:
%
s"
%
(
self
.
path
,
str
(
e
)))
# return the parsed yaml metadata
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
# now we do the actual extraction to the path
return
False
for
member
in
members
:
# we only extract files, and remove any relative path
# bits that might be in the file for security purposes
# and drop the leading directory, as mentioned above
if
member
.
isreg
()
or
member
.
issym
():
parts
=
member
.
name
.
split
(
os
.
sep
)[
1
:]
final_parts
=
[]
for
part
in
parts
:
if
part
!=
'..'
and
'~'
not
in
part
and
'$'
not
in
part
:
final_parts
.
append
(
part
)
member
.
name
=
os
.
path
.
join
(
*
final_parts
)
role_tar_file
.
extract
(
member
,
self
.
path
)
# write out the install info file for later use
self
.
_write_galaxy_install_info
()
except
OSError
as
e
:
display
.
error
(
"Could not update files in
%
s:
%
s"
%
(
self
.
path
,
str
(
e
)))
return
False
# return the parsed yaml metadata
display
.
display
(
"-
%
s was installed successfully"
%
self
.
name
)
return
True
@property
@property
def
spec
(
self
):
def
spec
(
self
):
...
@@ -266,65 +307,3 @@ class GalaxyRole(object):
...
@@ -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
lib/ansible/playbook/role/__init__.py
View file @
97c2b2ec
...
@@ -21,19 +21,14 @@ __metaclass__ = type
...
@@ -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
...
...
lib/ansible/playbook/role/requirement.py
View file @
97c2b2ec
...
@@ -19,11 +19,14 @@
...
@@ -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):
...
@@ -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):
...
@@ -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,102 +107,137 @@ class RoleRequirement(RoleDefinition):
...
@@ -104,102 +107,137 @@ class RoleRequirement(RoleDefinition):
return
ds
return
ds
def
repo_url_to_role_name
(
repo_url
):
@staticmethod
# gets the role name out of a repo like
def
repo_url_to_role_name
(
repo_url
):
# http://git.example.com/repos/repo.git" => "repo"
# gets the role name out of a repo like
# http://git.example.com/repos/repo.git" => "repo"
if
'://'
not
in
repo_url
and
'@'
not
in
repo_url
:
return
repo_url
if
'://'
not
in
repo_url
and
'@'
not
in
repo_url
:
trailing_path
=
repo_url
.
split
(
'/'
)[
-
1
]
return
repo_url
if
trailing_path
.
endswith
(
'.git'
):
trailing_path
=
repo_url
.
split
(
'/'
)[
-
1
]
trailing_path
=
trailing_path
[:
-
4
]
if
trailing_path
.
endswith
(
'.git'
):
if
trailing_path
.
endswith
(
'.tar.gz'
):
trailing_path
=
trailing_path
[:
-
4
]
trailing_path
=
trailing_path
[:
-
7
]
if
trailing_path
.
endswith
(
'.tar.gz'
):
if
','
in
trailing_path
:
trailing_path
=
trailing_path
[:
-
7
]
trailing_path
=
trailing_path
.
split
(
','
)[
0
]
if
','
in
trailing_path
:
return
trailing_path
trailing_path
=
trailing_path
.
split
(
','
)[
0
]
return
trailing_path
def
role_spec_parse
(
role_spec
):
# takes a repo and a version like
@staticmethod
# git+http://git.example.com/repos/repo.git,v1.0
def
role_spec_parse
(
role_spec
):
# and returns a list of properties such as:
# takes a repo and a version like
# {
# git+http://git.example.com/repos/repo.git,v1.0
# 'scm': 'git',
# and returns a list of properties such as:
# 'src': 'http://git.example.com/repos/repo.git',
# {
# 'version': 'v1.0',
# 'scm': 'git',
# 'name': 'repo'
# 'src': 'http://git.example.com/repos/repo.git',
# }
# 'version': 'v1.0',
# 'name': 'repo'
default_role_versions
=
dict
(
git
=
'master'
,
hg
=
'tip'
)
# }
role_spec
=
role_spec
.
strip
()
default_role_versions
=
dict
(
git
=
'master'
,
hg
=
'tip'
)
role_version
=
''
if
role_spec
==
""
or
role_spec
.
startswith
(
"#"
):
role_spec
=
role_spec
.
strip
()
return
(
None
,
None
,
None
,
None
)
role_version
=
''
if
role_spec
==
""
or
role_spec
.
startswith
(
"#"
):
tokens
=
[
s
.
strip
()
for
s
in
role_spec
.
split
(
','
)]
return
(
None
,
None
,
None
,
None
)
# assume https://github.com URLs are git+https:// URLs and not
tokens
=
[
s
.
strip
()
for
s
in
role_spec
.
split
(
','
)]
# tarballs unless they end in '.zip'
if
'github.com/'
in
tokens
[
0
]
and
not
tokens
[
0
]
.
startswith
(
"git+"
)
and
not
tokens
[
0
]
.
endswith
(
'.tar.gz'
):
# assume https://github.com URLs are git+https:// URLs and not
tokens
[
0
]
=
'git+'
+
tokens
[
0
]
# tarballs unless they end in '.zip'
if
'github.com/'
in
tokens
[
0
]
and
not
tokens
[
0
]
.
startswith
(
"git+"
)
and
not
tokens
[
0
]
.
endswith
(
'.tar.gz'
):
if
'+'
in
tokens
[
0
]:
tokens
[
0
]
=
'git+'
+
tokens
[
0
]
(
scm
,
role_url
)
=
tokens
[
0
]
.
split
(
'+'
)
else
:
if
'+'
in
tokens
[
0
]:
scm
=
None
(
scm
,
role_url
)
=
tokens
[
0
]
.
split
(
'+'
)
role_url
=
tokens
[
0
]
else
:
scm
=
None
if
len
(
tokens
)
>=
2
:
role_url
=
tokens
[
0
]
role_version
=
tokens
[
1
]
if
len
(
tokens
)
==
3
:
role_name
=
tokens
[
2
]
else
:
role_name
=
repo_url_to_role_name
(
tokens
[
0
])
if
scm
and
not
role_version
:
role_version
=
default_role_versions
.
get
(
scm
,
''
)
return
dict
(
scm
=
scm
,
src
=
role_url
,
version
=
role_version
,
role_name
=
role_name
)
# FIXME: all of these methods need to be cleaned up/reorganized below this
def
get_opt
(
options
,
k
,
defval
=
""
):
"""
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
):
"""
Returns the role path based on the roles_path option
and the role name.
"""
roles_path
=
get_opt
(
options
,
'roles_path'
)
roles_path
=
os
.
path
.
join
(
roles_path
,
role_name
)
roles_path
=
os
.
path
.
expanduser
(
roles_path
)
return
roles_path
def
get_role_metadata
(
role_name
,
options
):
if
len
(
tokens
)
>=
2
:
"""
role_version
=
tokens
[
1
]
Returns the metadata as YAML, if the file 'meta/main.yml'
exists in the specified role_path
if
len
(
tokens
)
==
3
:
"""
role_name
=
tokens
[
2
]
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
role_name
=
RoleRequirement
.
repo_url_to_role_name
(
tokens
[
0
])
except
:
return
None
if
scm
and
not
role_version
:
role_version
=
default_role_versions
.
get
(
scm
,
''
)
return
dict
(
scm
=
scm
,
src
=
role_url
,
version
=
role_version
,
name
=
role_name
)
@staticmethod
def
role_yaml_parse
(
role
):
if
'role'
in
role
:
# Old style: {role: "galaxy.role,version,name", other_vars: "here" }
role_info
=
RoleRequirement
.
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"
]
=
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
:
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
lib/ansible/utils/module_docs.py
View file @
97c2b2ec
...
@@ -63,6 +63,7 @@ def get_docstring(filename, verbose=False):
...
@@ -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):
...
@@ -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
test/integration/Makefile
View file @
97c2b2ec
...
@@ -172,7 +172,7 @@ test_galaxy: test_galaxy_spec test_galaxy_yaml
...
@@ -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:
...
@@ -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
=
$$
?
;
\
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment