diff options
author | Sloane Hertel <19572925+s-hertel@users.noreply.github.com> | 2022-10-26 17:05:17 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-26 16:05:17 -0500 |
commit | 65fd4e182ba1664deec04418af085db92cc6029b (patch) | |
tree | 5599f1e1a96ef55c3aaf2478bab19680e1797728 /lib | |
parent | a5480c330db2645c213081955273610b98c67a6c (diff) | |
download | ansible-65fd4e182ba1664deec04418af085db92cc6029b.tar.gz |
[2.13] ansible-galaxy - fix unnecessary api check when installing role (#79143)
* ansible-galaxy install - fix unnecessary api check when installing a role from git repo (#79090)
* delay server api evaluation until a GalaxyRole needs to make an api call for info, list, and install
(cherry picked from commit cb2e434dd2359a9fe1c00e75431f4abeff7381e8)
* fix type for older python
* Fix isinstance check (#79159)
Use GalaxyAPI for isinstance check instead of RoleDistributionServer, since the latter is defined in __main__ sometimes (when running integration tests or ansible-galaxy from source) and importing from ansible.cli.galaxy won't reference the same object.
(cherry picked from commit 89d682464b65af6d2f77a148fc6abb2c38b0e994)
Diffstat (limited to 'lib')
-rwxr-xr-x | lib/ansible/cli/galaxy.py | 62 | ||||
-rw-r--r-- | lib/ansible/galaxy/role.py | 9 |
2 files changed, 47 insertions, 24 deletions
diff --git a/lib/ansible/cli/galaxy.py b/lib/ansible/cli/galaxy.py index 5acaa6e46a..c08d2ec60f 100755 --- a/lib/ansible/cli/galaxy.py +++ b/lib/ansible/cli/galaxy.py @@ -17,7 +17,9 @@ import shutil import sys import textwrap import time +import typing as t +from dataclasses import dataclass from yaml.error import YAMLError import ansible.constants as C @@ -156,6 +158,30 @@ def validate_signature_count(value): return value +@dataclass +class RoleDistributionServer: + _api: t.Union[GalaxyAPI, None] + api_servers: t.List[GalaxyAPI] + + @property + def api(self): + if self._api: + return self._api + + for server in self.api_servers: + try: + if u'v1' in server.available_api_versions: + self._api = server + break + except Exception: + continue + + if not self._api: + self._api = self.api_servers[0] + + return self._api + + class GalaxyCLI(CLI): '''command to manage Ansible roles in shared repositories, the default of which is Ansible Galaxy *https://galaxy.ansible.com*.''' @@ -186,7 +212,7 @@ class GalaxyCLI(CLI): self.api_servers = [] self.galaxy = None - self._api = None + self.lazy_role_api = None super(GalaxyCLI, self).__init__(args) def init_parser(self): @@ -649,25 +675,15 @@ class GalaxyCLI(CLI): **galaxy_options )) + # checks api versions once a GalaxyRole makes an api call + # self.api can be used to evaluate the best server immediately + self.lazy_role_api = RoleDistributionServer(None, self.api_servers) + return context.CLIARGS['func']() @property def api(self): - if self._api: - return self._api - - for server in self.api_servers: - try: - if u'v1' in server.available_api_versions: - self._api = server - break - except Exception: - continue - - if not self._api: - self._api = self.api_servers[0] - - return self._api + return self.lazy_role_api.api def _get_default_collection_path(self): return C.COLLECTIONS_PATHS[0] @@ -728,7 +744,7 @@ class GalaxyCLI(CLI): display.vvv("found role %s in yaml file" % to_text(role)) if "name" not in role and "src" not in role: raise AnsibleError("Must specify name or src for role") - return [GalaxyRole(self.galaxy, self.api, **role)] + return [GalaxyRole(self.galaxy, self.lazy_role_api, **role)] else: b_include_path = to_bytes(requirement["include"], errors="surrogate_or_strict") if not os.path.isfile(b_include_path): @@ -737,7 +753,7 @@ class GalaxyCLI(CLI): with open(b_include_path, 'rb') as f_include: try: - return [GalaxyRole(self.galaxy, self.api, **r) for r in + return [GalaxyRole(self.galaxy, self.lazy_role_api, **r) for r in (RoleRequirement.role_yaml_parse(i) for i in yaml_load(f_include))] except Exception as e: raise AnsibleError("Unable to load data from include requirements file: %s %s" @@ -1152,7 +1168,7 @@ class GalaxyCLI(CLI): for role in context.CLIARGS['args']: role_info = {'path': roles_path} - gr = GalaxyRole(self.galaxy, self.api, role) + gr = GalaxyRole(self.galaxy, self.lazy_role_api, role) install_info = gr.install_info if install_info: @@ -1294,7 +1310,7 @@ class GalaxyCLI(CLI): # (and their dependencies, unless the user doesn't want us to). for rname in context.CLIARGS['args']: role = RoleRequirement.role_yaml_parse(rname.strip()) - role_requirements.append(GalaxyRole(self.galaxy, self.api, **role)) + role_requirements.append(GalaxyRole(self.galaxy, self.lazy_role_api, **role)) if not role_requirements and not collection_requirements: display.display("Skipping install, no requirements found") @@ -1403,7 +1419,7 @@ class GalaxyCLI(CLI): display.debug('Installing dep %s' % dep) dep_req = RoleRequirement() dep_info = dep_req.role_yaml_parse(dep) - dep_role = GalaxyRole(self.galaxy, self.api, **dep_info) + dep_role = GalaxyRole(self.galaxy, self.lazy_role_api, **dep_info) if '.' not in dep_role.name and '.' not in dep_role.src and dep_role.scm is None: # we know we can skip this, as it's not going to # be found on galaxy.ansible.com @@ -1487,7 +1503,7 @@ class GalaxyCLI(CLI): if role_name: # show the requested role, if it exists - gr = GalaxyRole(self.galaxy, self.api, role_name, path=os.path.join(role_path, role_name)) + gr = GalaxyRole(self.galaxy, self.lazy_role_api, role_name, path=os.path.join(role_path, role_name)) if os.path.isdir(gr.path): role_found = True display.display('# %s' % os.path.dirname(gr.path)) @@ -1506,7 +1522,7 @@ class GalaxyCLI(CLI): display.display('# %s' % role_path) path_files = os.listdir(role_path) for path_file in path_files: - gr = GalaxyRole(self.galaxy, self.api, path_file, path=path) + gr = GalaxyRole(self.galaxy, self.lazy_role_api, path_file, path=path) if gr.metadata: _display_role(gr) diff --git a/lib/ansible/galaxy/role.py b/lib/ansible/galaxy/role.py index 058174c931..391394cfc9 100644 --- a/lib/ansible/galaxy/role.py +++ b/lib/ansible/galaxy/role.py @@ -32,6 +32,7 @@ from shutil import rmtree from ansible import context from ansible.errors import AnsibleError +from ansible.galaxy.api import GalaxyAPI from ansible.galaxy.user_agent import user_agent from ansible.module_utils._text import to_native, to_text from ansible.module_utils.common.yaml import yaml_dump, yaml_load @@ -60,7 +61,7 @@ class GalaxyRole(object): display.debug('Validate TLS certificates: %s' % self._validate_certs) self.galaxy = galaxy - self.api = api + self._api = api self.name = name self.version = version @@ -101,6 +102,12 @@ class GalaxyRole(object): return self.name == other.name @property + def api(self): + if not isinstance(self._api, GalaxyAPI): + return self._api.api + return self._api + + @property def metadata(self): """ Returns role metadata |