Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API now connects to server lazily #15632

Merged
merged 1 commit into from
Apr 29, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 5 additions & 9 deletions lib/ansible/cli/galaxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class GalaxyCLI(CLI):

SKIP_INFO_KEYS = ("name", "description", "readme_html", "related", "summary_fields", "average_aw_composite", "average_aw_score", "url" )
VALID_ACTIONS = ("delete", "import", "info", "init", "install", "list", "login", "remove", "search", "setup")

def __init__(self, args):
self.api = None
self.galaxy = None
Expand Down Expand Up @@ -146,14 +146,10 @@ def parse(self):
return True

def run(self):

super(GalaxyCLI, self).run()

# if not offline, get connect to galaxy api
if self.action in ("import","info","install","search","login","setup","delete") or \
(self.action == 'init' and not self.options.offline):
self.api = GalaxyAPI(self.galaxy)
super(GalaxyCLI, self).run()

self.api = GalaxyAPI(self.galaxy)
self.execute()

def exit_without_ignore(self, rc=1):
Expand Down Expand Up @@ -242,7 +238,7 @@ def execute_init(self):
# platforms included (but commented out), the galaxy_tags
# list, and the dependencies section
platforms = []
if not offline and self.api:
if not offline:
platforms = self.api.get_list("platforms") or []

# group the list of platforms from the api based
Expand Down Expand Up @@ -315,7 +311,7 @@ def execute_info(self):
role_info.update(install_info)

remote_data = False
if self.api:
if not self.options.offline:
remote_data = self.api.lookup_role_by_name(role, False)

if remote_data:
Expand Down
56 changes: 38 additions & 18 deletions lib/ansible/galaxy/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import urllib

from urllib2 import quote as urlquote, HTTPError
from urlparse import urlparse

import ansible.constants as C
from ansible.errors import AnsibleError
Expand All @@ -41,6 +40,21 @@
from ansible.utils.display import Display
display = Display()

def g_connect(method):
''' wrapper to lazily initialize connection info to galaxy '''
def wrapped(self, *args, **kwargs):
if not self.initialized:
display.vvvv("Initial connection to galaxy_server: %s" % self._api_server)
server_version = self._get_server_api_version()
if not server_version in self.SUPPORTED_VERSIONS:
raise AnsibleError("Unsupported Galaxy server API version: %s" % server_version)

self.baseurl = '%s/api/%s' % (self._api_server, server_version)
self.version = server_version # for future use
display.vvvv("Base API: %s" % self.baseurl)
self.initialized = True
return method(self, *args, **kwargs)
return wrapped

class GalaxyAPI(object):
''' This class is meant to be used as a API client for an Ansible Galaxy server '''
Expand All @@ -52,6 +66,9 @@ def __init__(self, galaxy):
self.token = GalaxyToken()
self._api_server = C.GALAXY_SERVER
self._validate_certs = not C.GALAXY_IGNORE_CERTS
self.baseurl = None
self.version = None
self.initialized = False

# set validate_certs
if galaxy.options.ignore_certs:
Expand All @@ -61,22 +78,15 @@ def __init__(self, galaxy):
# set the API server
if galaxy.options.api_server != C.GALAXY_SERVER:
self._api_server = galaxy.options.api_server
display.vvv("Connecting to galaxy_server: %s" % self._api_server)

server_version = self.get_server_api_version()
if not server_version in self.SUPPORTED_VERSIONS:
raise AnsibleError("Unsupported Galaxy server API version: %s" % server_version)

self.baseurl = '%s/api/%s' % (self._api_server, server_version)
self.version = server_version # for future use
display.vvv("Base API: %s" % self.baseurl)

def __auth_header(self):
token = self.token.get()
if token is None:
raise AnsibleError("No access token. You must first use login to authenticate and obtain an access token.")
return {'Authorization': 'Token ' + token}

@g_connect
def __call_galaxy(self, url, args=None, headers=None, method=None):
if args and not headers:
headers = self.__auth_header()
Expand All @@ -91,13 +101,13 @@ def __call_galaxy(self, url, args=None, headers=None, method=None):

@property
def api_server(self):
return self._api_server
return self._api_server

@property
def validate_certs(self):
return self._validate_certs

def get_server_api_version(self):
def _get_server_api_version(self):
"""
Fetches the Galaxy API current version to ensure
the API server is up and reachable.
Expand All @@ -107,8 +117,9 @@ def get_server_api_version(self):
data = json.load(open_url(url, validate_certs=self._validate_certs))
return data['current_version']
except Exception as e:
raise AnsibleError("The API server (%s) is not responding, please try again later." % url)

raise AnsibleError("The API server (%s) is not responding, please try again later" % url)

@g_connect
def authenticate(self, github_token):
"""
Retrieve an authentication token
Expand All @@ -134,6 +145,7 @@ def create_import_task(self, github_user, github_repo, reference=None):
return data['results']
return data

@g_connect
def get_import_task(self, task_id=None, github_user=None, github_repo=None):
"""
Check the status of an import task.
Expand All @@ -145,10 +157,11 @@ def get_import_task(self, task_id=None, github_user=None, github_repo=None):
url = "%s?github_user=%s&github_repo=%s" % (url,github_user,github_repo)
else:
raise AnsibleError("Expected task_id or github_user and github_repo")

data = self.__call_galaxy(url)
return data['results']


@g_connect
def lookup_role_by_name(self, role_name, notify=True):
"""
Find a role by name.
Expand All @@ -170,6 +183,7 @@ def lookup_role_by_name(self, role_name, notify=True):
return data["results"][0]
return None

@g_connect
def fetch_role_related(self, related, role_id):
"""
Fetch the list of related items for the given role.
Expand All @@ -190,6 +204,7 @@ def fetch_role_related(self, related, role_id):
except:
return None

@g_connect
def get_list(self, what):
"""
Fetch the list of items specified.
Expand All @@ -213,6 +228,7 @@ def get_list(self, what):
except Exception as error:
raise AnsibleError("Failed to download the %s list: %s" % (what, str(error)))

@g_connect
def search_roles(self, search, **kwargs):

search_url = self.baseurl + '/search/roles/?'
Expand All @@ -228,7 +244,7 @@ def search_roles(self, search, **kwargs):
if tags and isinstance(tags, basestring):
tags = tags.split(',')
search_url += '&tags_autocomplete=' + '+'.join(tags)

if platforms and isinstance(platforms, basestring):
platforms = platforms.split(',')
search_url += '&platforms_autocomplete=' + '+'.join(platforms)
Expand All @@ -238,10 +254,11 @@ def search_roles(self, search, **kwargs):

if author:
search_url += '&username_autocomplete=%s' % author

data = self.__call_galaxy(search_url)
return data

@g_connect
def add_secret(self, source, github_user, github_repo, secret):
url = "%s/notification_secrets/" % self.baseurl
args = urllib.urlencode({
Expand All @@ -253,16 +270,19 @@ def add_secret(self, source, github_user, github_repo, secret):
data = self.__call_galaxy(url, args=args)
return data

@g_connect
def list_secrets(self):
url = "%s/notification_secrets" % self.baseurl
data = self.__call_galaxy(url, headers=self.__auth_header())
return data

@g_connect
def remove_secret(self, secret_id):
url = "%s/notification_secrets/%s/" % (self.baseurl, secret_id)
data = self.__call_galaxy(url, headers=self.__auth_header(), method='DELETE')
return data

@g_connect
def delete_role(self, github_user, github_repo):
url = "%s/removerole/?github_user=%s&github_repo=%s" % (self.baseurl,github_user,github_repo)
data = self.__call_galaxy(url, headers=self.__auth_header(), method='DELETE')
Expand Down