API now connects to server lazily (#15632)

This should fix most issues with offline operation.

Fixes #14486
Fixes #13991

Alternate to #15363 and #15593
pull/15759/head
Brian Coca 9 years ago committed by Brian Coca
parent 5a9e826647
commit 74b4d7a2ae

@ -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
@ -146,14 +146,10 @@ class GalaxyCLI(CLI):
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):
@ -242,7 +238,7 @@ class GalaxyCLI(CLI):
# 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
@ -315,7 +311,7 @@ class GalaxyCLI(CLI):
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:

@ -28,7 +28,6 @@ import json
import urllib
from urllib2 import quote as urlquote, HTTPError
from urlparse import urlparse
import ansible.constants as C
from ansible.errors import AnsibleError
@ -41,6 +40,21 @@ except ImportError:
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 '''
@ -52,6 +66,9 @@ class GalaxyAPI(object):
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:
@ -61,15 +78,7 @@ class GalaxyAPI(object):
# 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()
@ -77,6 +86,7 @@ class GalaxyAPI(object):
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()
@ -91,13 +101,13 @@ class GalaxyAPI(object):
@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.
@ -107,8 +117,9 @@ class GalaxyAPI(object):
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
@ -134,6 +145,7 @@ class GalaxyAPI(object):
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.
@ -145,10 +157,11 @@ class GalaxyAPI(object):
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.
@ -170,6 +183,7 @@ class GalaxyAPI(object):
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.
@ -190,6 +204,7 @@ class GalaxyAPI(object):
except:
return None
@g_connect
def get_list(self, what):
"""
Fetch the list of items specified.
@ -213,6 +228,7 @@ class GalaxyAPI(object):
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/?'
@ -228,7 +244,7 @@ class GalaxyAPI(object):
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)
@ -238,10 +254,11 @@ class GalaxyAPI(object):
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({
@ -253,16 +270,19 @@ class GalaxyAPI(object):
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')

Loading…
Cancel
Save