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
6ffd9c30
Commit
6ffd9c30
authored
Aug 22, 2015
by
Brian Coca
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
draft galaxy cli search
TODO: paging results
parent
e282309f
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
137 additions
and
80 deletions
+137
-80
lib/ansible/cli/galaxy.py
+104
-78
lib/ansible/galaxy/api.py
+33
-2
No files found.
lib/ansible/cli/galaxy.py
View file @
6ffd9c30
...
...
@@ -19,23 +19,14 @@
#
########################################################################
import
datetime
import
json
import
os
import
os.path
import
shutil
import
subprocess
import
sys
import
tarfile
import
tempfile
import
urllib
import
urllib2
import
yaml
from
collections
import
defaultdict
from
distutils.version
import
LooseVersion
from
jinja2
import
Environment
from
optparse
import
OptionParser
import
ansible.constants
as
C
import
ansible.utils
...
...
@@ -46,12 +37,12 @@ from ansible.galaxy import Galaxy
from
ansible.galaxy.api
import
GalaxyAPI
from
ansible.galaxy.role
import
GalaxyRole
from
ansible.playbook.role.requirement
import
RoleRequirement
from
ansible.utils.display
import
Display
class
GalaxyCLI
(
CLI
):
VALID_ACTIONS
=
(
"init"
,
"info"
,
"install"
,
"list"
,
"remove"
)
SKIP_INFO_KEYS
=
(
"
platforms"
,
"readme_html"
,
"related"
,
"summary_fields"
,
"average_aw_composite"
,
"average_aw_score"
,
"url"
)
VALID_ACTIONS
=
(
"init"
,
"info"
,
"install"
,
"list"
,
"remove"
,
"search"
)
SKIP_INFO_KEYS
=
(
"
name"
,
"description"
,
"readme_html"
,
"related"
,
"summary_fields"
,
"average_aw_composite"
,
"average_aw_score"
,
"url"
)
def
__init__
(
self
,
args
,
display
=
None
):
...
...
@@ -72,47 +63,46 @@ class GalaxyCLI(CLI):
# options specific to actions
if
self
.
action
==
"info"
:
self
.
parser
.
set_usage
(
"usage:
%
prog info [options] role_name[,version]"
)
self
.
parser
.
set_usage
(
"usage:
%
prog info [options] role_name[,version]"
)
elif
self
.
action
==
"init"
:
self
.
parser
.
set_usage
(
"usage:
%
prog init [options] role_name"
)
self
.
parser
.
add_option
(
'-p'
,
'--init-path'
,
dest
=
'init_path'
,
default
=
"./"
,
help
=
'The path in which the skeleton role will be created. '
'The default is the current working directory.'
)
self
.
parser
.
add_option
(
self
.
parser
.
set_usage
(
"usage:
%
prog init [options] role_name"
)
self
.
parser
.
add_option
(
'-p'
,
'--init-path'
,
dest
=
'init_path'
,
default
=
"./"
,
help
=
'The path in which the skeleton role will be created. The default is the current working directory.'
)
self
.
parser
.
add_option
(
'--offline'
,
dest
=
'offline'
,
default
=
False
,
action
=
'store_true'
,
help
=
"Don't query the galaxy API when creating roles"
)
elif
self
.
action
==
"install"
:
self
.
parser
.
set_usage
(
"usage:
%
prog install [options] [-r FILE | role_name(s)[,version] | scm+role_repo_url[,version] | tar_file(s)]"
)
self
.
parser
.
add_option
(
'-i'
,
'--ignore-errors'
,
dest
=
'ignore_errors'
,
action
=
'store_true'
,
default
=
False
,
self
.
parser
.
set_usage
(
"usage:
%
prog install [options] [-r FILE | role_name(s)[,version] | scm+role_repo_url[,version] | tar_file(s)]"
)
self
.
parser
.
add_option
(
'-i'
,
'--ignore-errors'
,
dest
=
'ignore_errors'
,
action
=
'store_true'
,
default
=
False
,
help
=
'Ignore errors and continue with the next specified role.'
)
self
.
parser
.
add_option
(
'-n'
,
'--no-deps'
,
dest
=
'no_deps'
,
action
=
'store_true'
,
default
=
False
,
self
.
parser
.
add_option
(
'-n'
,
'--no-deps'
,
dest
=
'no_deps'
,
action
=
'store_true'
,
default
=
False
,
help
=
'Don
\'
t download roles listed as dependencies'
)
self
.
parser
.
add_option
(
'-r'
,
'--role-file'
,
dest
=
'role_file'
,
self
.
parser
.
add_option
(
'-r'
,
'--role-file'
,
dest
=
'role_file'
,
help
=
'A file containing a list of roles to be imported'
)
elif
self
.
action
==
"remove"
:
self
.
parser
.
set_usage
(
"usage:
%
prog remove role1 role2 ..."
)
self
.
parser
.
set_usage
(
"usage:
%
prog remove role1 role2 ..."
)
elif
self
.
action
==
"list"
:
self
.
parser
.
set_usage
(
"usage:
%
prog list [role_name]"
)
self
.
parser
.
set_usage
(
"usage:
%
prog list [role_name]"
)
elif
self
.
action
==
"search"
:
self
.
parser
.
add_option
(
'-P'
,
'--platforms'
,
dest
=
'platforms'
,
help
=
'list of OS platforms to filter by'
)
self
.
parser
.
add_option
(
'-C'
,
'--categories'
,
dest
=
'categories'
,
help
=
'list of categories to filter by'
)
self
.
parser
.
set_usage
(
"usage:
%
prog search [<search_term>] [-C <category1,category2>] [-P platform]"
)
# options that apply to more than one action
if
self
.
action
!=
"init"
:
self
.
parser
.
add_option
(
'-p'
,
'--roles-path'
,
dest
=
'roles_path'
,
default
=
C
.
DEFAULT_ROLES_PATH
,
self
.
parser
.
add_option
(
'-p'
,
'--roles-path'
,
dest
=
'roles_path'
,
default
=
C
.
DEFAULT_ROLES_PATH
,
help
=
'The path to the directory containing your roles. '
'The default is the roles_path configured in your '
'ansible.cfg file (/etc/ansible/roles if not configured)'
)
if
self
.
action
in
(
"info"
,
"init"
,
"install"
):
self
.
parser
.
add_option
(
'-s'
,
'--server'
,
dest
=
'api_server'
,
default
=
"https://galaxy.ansible.com"
,
if
self
.
action
in
(
"info"
,
"init"
,
"install"
,
"search"
):
self
.
parser
.
add_option
(
'-s'
,
'--server'
,
dest
=
'api_server'
,
default
=
"https://galaxy.ansible.com"
,
help
=
'The API server destination'
)
if
self
.
action
in
(
"init"
,
"install"
):
self
.
parser
.
add_option
(
'-f'
,
'--force'
,
dest
=
'force'
,
action
=
'store_true'
,
default
=
False
,
self
.
parser
.
add_option
(
'-f'
,
'--force'
,
dest
=
'force'
,
action
=
'store_true'
,
default
=
False
,
help
=
'Force overwriting an existing role'
)
# get options, args and galaxy object
...
...
@@ -127,7 +117,7 @@ class GalaxyCLI(CLI):
super
(
GalaxyCLI
,
self
)
.
run
()
# if not offline, get connect to galaxy api
if
self
.
action
in
(
"info"
,
"install"
)
or
(
self
.
action
==
'init'
and
not
self
.
options
.
offline
):
if
self
.
action
in
(
"info"
,
"install"
,
"search"
)
or
(
self
.
action
==
'init'
and
not
self
.
options
.
offline
):
api_server
=
self
.
options
.
api_server
self
.
api
=
GalaxyAPI
(
self
.
galaxy
,
api_server
)
if
not
self
.
api
:
...
...
@@ -156,6 +146,65 @@ class GalaxyCLI(CLI):
if
not
self
.
get_opt
(
"ignore_errors"
,
False
):
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
):
text
=
"
\n
Role:
%
s
\n
"
%
role_info
[
'name'
]
text
+=
"
\t
description:
%
s
\n
"
%
role_info
[
'description'
]
for
k
in
sorted
(
role_info
.
keys
()):
if
k
in
self
.
SKIP_INFO_KEYS
:
continue
if
isinstance
(
role_info
[
k
],
dict
):
text
+=
"
\t
%
s:
\n
"
%
(
k
)
for
key
in
sorted
(
role_info
[
k
]
.
keys
()):
if
key
in
self
.
SKIP_INFO_KEYS
:
continue
text
+=
"
\t\t
%
s:
%
s
\n
"
%
(
key
,
role_info
[
k
][
key
])
else
:
text
+=
"
\t
%
s:
%
s
\n
"
%
(
k
,
role_info
[
k
])
return
text
############################
# execute actions
############################
def
execute_init
(
self
):
"""
Executes the init action, which creates the skeleton framework
...
...
@@ -249,6 +298,7 @@ class GalaxyCLI(CLI):
roles_path
=
self
.
get_opt
(
"roles_path"
)
data
=
''
for
role
in
self
.
args
:
role_info
=
{}
...
...
@@ -277,23 +327,12 @@ class GalaxyCLI(CLI):
if
role_spec
:
role_info
.
update
(
role_spec
)
if
role_info
:
self
.
display
.
display
(
"-
%
s:"
%
(
role
))
for
k
in
sorted
(
role_info
.
keys
()):
if
k
in
self
.
SKIP_INFO_KEYS
:
continue
if
isinstance
(
role_info
[
k
],
dict
):
self
.
display
.
display
(
"
\t
%
s: "
%
(
k
))
for
key
in
sorted
(
role_info
[
k
]
.
keys
()):
if
key
in
self
.
SKIP_INFO_KEYS
:
continue
self
.
display
.
display
(
"
\t\t
%
s:
%
s"
%
(
key
,
role_info
[
k
][
key
]))
else
:
self
.
display
.
display
(
"
\t
%
s:
%
s"
%
(
k
,
role_info
[
k
]))
data
+=
self
.
_display_role_info
(
role_info
)
if
data
:
data
+=
"
\n
-
%
s:"
%
(
role
)
else
:
self
.
display
.
display
(
"- the role
%
s was not found"
%
role
)
data
+=
"
\n
- the role
%
s was not found"
%
role
self
.
pager
(
data
)
def
execute_install
(
self
):
"""
...
...
@@ -497,35 +536,22 @@ class GalaxyCLI(CLI):
self
.
display
.
display
(
"-
%
s,
%
s"
%
(
path_file
,
version
))
return
0
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"
]
def
execute_search
(
self
):
if
'+'
in
role
[
"src"
]:
(
scm
,
src
)
=
role
[
"src"
]
.
split
(
'+'
)
role
[
"scm"
]
=
scm
role
[
"src"
]
=
src
search
=
None
if
len
(
self
.
args
)
>
1
:
raise
AnsibleOptionsError
(
"At most a single search term is allowed."
)
elif
len
(
self
.
args
)
==
1
:
search
=
self
.
args
.
pop
()
if
'name'
not
in
role
:
role
[
"name"
]
=
GalaxyRole
.
url_to_spec
(
role
[
"src"
])
response
=
self
.
api
.
search_roles
(
search
,
self
.
options
.
platforms
,
self
.
options
.
categories
)
if
'version'
not
in
rol
e
:
role
[
'version'
]
=
''
if
'count'
in
respons
e
:
self
.
galaxy
.
display
.
display
(
"Found
%
d roles matching your search:
\n
"
%
response
[
'count'
])
if
'scm'
not
in
role
:
role
[
'scm'
]
=
None
data
=
''
if
'results'
in
response
:
for
role
in
response
[
'results'
]:
data
+=
self
.
_display_role_info
(
role
)
return
role
self
.
pager
(
data
)
lib/ansible/galaxy/api.py
View file @
6ffd9c30
...
...
@@ -21,10 +21,10 @@
#
########################################################################
import
json
from
urllib2
import
urlopen
,
quote
as
urlquote
from
urllib2
import
urlopen
,
quote
as
urlquote
,
HTTPError
from
urlparse
import
urlparse
from
ansible.errors
import
AnsibleError
from
ansible.errors
import
AnsibleError
,
AnsibleOptionsError
class
GalaxyAPI
(
object
):
''' This class is meant to be used as a API client for an Ansible Galaxy server '''
...
...
@@ -139,3 +139,34 @@ class GalaxyAPI(object):
return
results
except
Exception
as
error
:
raise
AnsibleError
(
"Failed to download the
%
s list:
%
s"
%
(
what
,
str
(
error
)))
def
search_roles
(
self
,
search
,
platforms
=
None
,
categories
=
None
):
search_url
=
self
.
baseurl
+
'/roles/?page=1'
if
search
:
search_url
+=
'&search='
+
urlquote
(
search
)
if
categories
is
None
:
categories
=
[]
elif
isinstance
(
categories
,
basestring
):
categories
=
categories
.
split
(
','
)
for
cat
in
categories
:
search_url
+=
'&chain__categories__name='
+
urlquote
(
cat
)
if
platforms
is
None
:
platforms
=
[]
elif
isinstance
(
platforms
,
basestring
):
platforms
=
platforms
.
split
(
','
)
for
plat
in
platforms
:
search_url
+=
'&chain__platforms__name='
+
urlquote
(
plat
)
self
.
galaxy
.
display
.
debug
(
"Executing query:
%
s"
%
search_url
)
try
:
data
=
json
.
load
(
urlopen
(
search_url
))
except
HTTPError
as
e
:
raise
AnsibleError
(
"Unsuccessful request to server:
%
s"
%
str
(
e
))
return
data
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