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

Ansible-galaxy API client ignoring latest and reads all versions #79467

Closed
1 task done
tibeer opened this issue Nov 25, 2022 · 17 comments
Closed
1 task done

Ansible-galaxy API client ignoring latest and reads all versions #79467

tibeer opened this issue Nov 25, 2022 · 17 comments
Labels
affects_2.13 bug This issue/PR relates to a bug. P3 Priority 3 - Approved, No Time Limitation

Comments

@tibeer
Copy link

tibeer commented Nov 25, 2022

Summary

When trying to install a ansible-galaxy collection, the API client ignores the latest version which is provided on the API endpoint: https://galaxy.ansible.com/api/v2/collections/osism/services/.
It rather skips that information and continues to the versions endpoint: https://galaxy.ansible.com/api/v2/collections/osism/services/versions/.
After doing this, every single version is fetched individually just to continue using the latest alphabetical version.
When one decides to change the versioning scheme (e.g. from previous vX.X.X to X.X.X) always the latest vX.X.X would still be used as it is ordered alphabetically by the client.

This might also be a misunderstanding on my side, but it seems quite awkward to me that every single version JSON manifest is fetched. On collections with a lot versions this introduces unnecessary delay and can even (as described before) lead to malfunctioning.

Issue Type

Bug Report

Component Name

ansible-galaxy

Ansible Version

$ ansible --version
ansible [core 2.13.6]
  config file = None
  configured module search path = ['/Users/foobar/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /opt/homebrew/Cellar/ansible/6.6.0/libexec/lib/python3.10/site-packages/ansible
  ansible collection location = /Users/foobar/.ansible/collections:/usr/share/ansible/collections
  executable location = /opt/homebrew/bin/ansible
  python version = 3.10.8 (main, Oct 13 2022, 09:48:40) [Clang 14.0.0 (clang-1400.0.29.102)]
  jinja version = 3.1.2
  libyaml = True

Configuration

# if using a version older than ansible-core 2.12 you should omit the '-t all'
$ ansible-config dump --only-changed -t all

$ # Nothing changed

OS / Environment

macOS 13.0.1

Steps to Reproduce

$ rm -rf ~/.ansible; ansible-galaxy collection install -s official osism.services -vvvv
ansible-galaxy [core 2.13.6]
  config file = None
  configured module search path = ['/Users/foobar/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /opt/homebrew/Cellar/ansible/6.6.0/libexec/lib/python3.10/site-packages/ansible
  ansible collection location = /Users/foobar/.ansible/collections:/usr/share/ansible/collections
  executable location = /opt/homebrew/bin/ansible-galaxy
  python version = 3.10.8 (main, Oct 13 2022, 09:48:40) [Clang 14.0.0 (clang-1400.0.29.102)]
  jinja version = 3.1.2
  libyaml = True
No config file found; using defaults
Creating Galaxy API response cache file at '/Users/foobar/.ansible/galaxy_cache/api.json'
Galaxy cache file at '/Users/foobar/.ansible/galaxy_cache/api.json' has an invalid version, clearing
Starting galaxy collection install process
Process install dependency map
Initial connection to galaxy_server: https://galaxy.ansible.com/
Created /Users/foobar/.ansible/galaxy_token
Calling Galaxy at https://galaxy.ansible.com/api/
Found API version 'v1, v2' with Galaxy server official (https://galaxy.ansible.com/api/)
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/?page_size=100
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.9.4/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.10.0/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.9.1/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.9.0/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.2.0/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.1.0/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.7.0/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.9.2/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.9.3/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.8.0/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.3.0/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.0.1/
Starting collection install process
Fetching a collection tarball for 'osism.services:0.10.0' from Ansible Galaxy
Downloading https://galaxy.ansible.com/download/osism-services-0.10.0.tar.gz to /Users/foobar/.ansible/tmp/ansible-local-28120sgilekqr/tmp0qvaavan/osism-services-0.10.0-g37qrel1
Validating downloaded file hash ad5bd77fd3c0eca2c01b58facd6d76dd524aa6ae67a553f67a630db1e59c2773 with expected hash ad5bd77fd3c0eca2c01b58facd6d76dd524aa6ae67a553f67a630db1e59c2773
Collection 'osism.services:0.10.0' obtained from server official https://galaxy.ansible.com/api/
Installing 'osism.services:0.10.0' to '/Users/foobar/.ansible/collections/ansible_collections/osism/services'
osism.services:0.10.0 was installed successfully

Expected Results

Only the latest Version should be called, the output should look like this:

$ rm -rf ~/.ansible; ansible-galaxy collection install -s official osism.services -vvvv
ansible-galaxy [core 2.13.6]
  config file = None
  configured module search path = ['/Users/foobar/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /opt/homebrew/Cellar/ansible/6.6.0/libexec/lib/python3.10/site-packages/ansible
  ansible collection location = /Users/foobar/.ansible/collections:/usr/share/ansible/collections
  executable location = /opt/homebrew/bin/ansible-galaxy
  python version = 3.10.8 (main, Oct 13 2022, 09:48:40) [Clang 14.0.0 (clang-1400.0.29.102)]
  jinja version = 3.1.2
  libyaml = True
No config file found; using defaults
Creating Galaxy API response cache file at '/Users/foobar/.ansible/galaxy_cache/api.json'
Galaxy cache file at '/Users/foobar/.ansible/galaxy_cache/api.json' has an invalid version, clearing
Starting galaxy collection install process
Process install dependency map
Initial connection to galaxy_server: https://galaxy.ansible.com/
Created /Users/foobar/.ansible/galaxy_token
Calling Galaxy at https://galaxy.ansible.com/api/
Found API version 'v1, v2' with Galaxy server official (https://galaxy.ansible.com/api/)
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.10.0/
Starting collection install process
Fetching a collection tarball for 'osism.services:0.10.0' from Ansible Galaxy
Downloading https://galaxy.ansible.com/download/osism-services-0.10.0.tar.gz to /Users/foobar/.ansible/tmp/ansible-local-28120sgilekqr/tmp0qvaavan/osism-services-0.10.0-g37qrel1
Validating downloaded file hash ad5bd77fd3c0eca2c01b58facd6d76dd524aa6ae67a553f67a630db1e59c2773 with expected hash ad5bd77fd3c0eca2c01b58facd6d76dd524aa6ae67a553f67a630db1e59c2773
Collection 'osism.services:0.10.0' obtained from server official https://galaxy.ansible.com/api/
Installing 'osism.services:0.10.0' to '/Users/foobar/.ansible/collections/ansible_collections/osism/services'
osism.services:0.10.0 was installed successfully

Actual Results

$ rm -rf ~/.ansible; ansible-galaxy collection install -s official osism.services -vvvv
ansible-galaxy [core 2.13.6]
  config file = None
  configured module search path = ['/Users/foobar/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /opt/homebrew/Cellar/ansible/6.6.0/libexec/lib/python3.10/site-packages/ansible
  ansible collection location = /Users/foobar/.ansible/collections:/usr/share/ansible/collections
  executable location = /opt/homebrew/bin/ansible-galaxy
  python version = 3.10.8 (main, Oct 13 2022, 09:48:40) [Clang 14.0.0 (clang-1400.0.29.102)]
  jinja version = 3.1.2
  libyaml = True
No config file found; using defaults
Creating Galaxy API response cache file at '/Users/foobar/.ansible/galaxy_cache/api.json'
Galaxy cache file at '/Users/foobar/.ansible/galaxy_cache/api.json' has an invalid version, clearing
Starting galaxy collection install process
Process install dependency map
Initial connection to galaxy_server: https://galaxy.ansible.com/
Created /Users/foobar/.ansible/galaxy_token
Calling Galaxy at https://galaxy.ansible.com/api/
Found API version 'v1, v2' with Galaxy server official (https://galaxy.ansible.com/api/)
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/?page_size=100
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.9.4/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.10.0/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.9.1/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.9.0/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.2.0/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.1.0/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.7.0/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.9.2/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.9.3/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.8.0/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.3.0/
Calling Galaxy at https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.0.1/
Starting collection install process
Fetching a collection tarball for 'osism.services:0.10.0' from Ansible Galaxy
Downloading https://galaxy.ansible.com/download/osism-services-0.10.0.tar.gz to /Users/foobar/.ansible/tmp/ansible-local-28120sgilekqr/tmp0qvaavan/osism-services-0.10.0-g37qrel1
Validating downloaded file hash ad5bd77fd3c0eca2c01b58facd6d76dd524aa6ae67a553f67a630db1e59c2773 with expected hash ad5bd77fd3c0eca2c01b58facd6d76dd524aa6ae67a553f67a630db1e59c2773
Collection 'osism.services:0.10.0' obtained from server official https://galaxy.ansible.com/api/
Installing 'osism.services:0.10.0' to '/Users/foobar/.ansible/collections/ansible_collections/osism/services'
osism.services:0.10.0 was installed successfully

Code of Conduct

  • I agree to follow the Ansible Code of Conduct
@ansibot
Copy link
Contributor

ansibot commented Nov 25, 2022

Files identified in the description:

  • lib/ansible/galaxy

If these files are incorrect, please update the component name section of the description or use the !component bot command.

click here for bot help

@ansibot ansibot added affects_2.13 bug This issue/PR relates to a bug. needs_triage Needs a first human triage before being processed. labels Nov 25, 2022
@s-hertel
Copy link
Contributor

This happens because when multiple collections are installed, we need to find a version that is compatible with all requirements. Since Galaxy doesn't give versions in order, ansible-galaxy collects all of them.

You can work around this by installing a specific version, like ansible-galaxy collection install "osism.services:==0.10.0".

ansible-galaxy could possibly optimize this by checking first if the latest version would match all requirements and only retrieving versions if it doesn't.

@tibeer
Copy link
Author

tibeer commented Nov 28, 2022

@s-hertel thanks for the info. I guess than that this API endpoint:

https://galaxy.ansible.com/api/v2/collections/osism/services/

which offers this stanca:

    "latest_version": {
        "version": "0.10.0",
        "href": "https://galaxy.ansible.com/api/v2/collections/osism/services/versions/0.10.0/"
    },

Is not used at the moment, am I correct?

@s-hertel
Copy link
Contributor

@tibeer That's correct.

@tibeer
Copy link
Author

tibeer commented Nov 28, 2022

Thanks, I'll close this!

@tibeer tibeer closed this as completed Nov 28, 2022
@s-hertel
Copy link
Contributor

s-hertel commented Nov 28, 2022

@tibeer You could leave it open imo, it seems like a reasonable thing to improve. I may not get to it quickly, but if anyone else is interested in picking this up basically we'd just need to refactor this function https://github.com/ansible/ansible/blob/stable-2.14/lib/ansible/galaxy/dependency_resolution/providers.py#L309. Rather than immediately getting all versions https://github.com/ansible/ansible/blob/stable-2.14/lib/ansible/galaxy/dependency_resolution/providers.py#L331, first try with the latest_version information (backwards compatible because we prefer the latest version anyway) and if no match is found, then fall back to the existing behavior. Prereleases might need some special handling (if latest_version is a prerelease, it shouldn't be used unless --pre is provided).

@tibeer tibeer reopened this Nov 28, 2022
@mkrizek mkrizek added P3 Priority 3 - Approved, No Time Limitation and removed needs_triage Needs a first human triage before being processed. labels Nov 29, 2022
@cigamit
Copy link
Contributor

cigamit commented Jan 6, 2023

I just ran into this issue. Was trying to determine why when downloading the community.general collection, my project sync was taking 17 minutes. Pinning it a specific version in my requirements file dropped the sync to 44 seconds. That is a huge difference.

Was using command line galaxy to debug, and noticed that it was querying the dependency map for every single version (and there are a ton on that collection). With the number of versions only ever increasing going forward, I definitely think this needs to be implemented sooner rather than later.

@cigamit
Copy link
Contributor

cigamit commented Jan 6, 2023

I would also note that if I don't specify a version, I would expect it to always pull the latest version, and only the latest version. That is also what it seems the documentation implies will happen (* = latest). If there is a dependency issue with that latest version, I would rather it failed and alerted me to such an issue, so that I can make note of if and can pin proper versions. What happens instead if there is a dependency issue, is that it downgrades it to an older version, without alerting us to the fact. So I think I am using the latest version of a collection, but instead I am not. I may have needed the latest version of that 1st collection for a reason and will spent time debugging why my playbook no longer works because I didn't know the version was downgraded.

I would think the existing behavior should only be used if I specifically tell it I want a version greater than X or lower than Y, etc... If I tell you I want a compatible version between these 2 numbers (or between this version and the latest), then you should look for one, otherwise you should get only the version I specified or the latest if I didn't specify.

@webknjaz
Copy link
Member

If there is a dependency issue with that latest version, I would rather it failed and alerted me to such an issue, so that I can make note of if and can pin proper versions. What happens instead if there is a dependency issue, is that it downgrades it to an older version, without alerting us to the fact. So I think I am using the latest version of a collection, but instead I am not. I may have needed the latest version of that 1st collection for a reason and will spent time debugging why my playbook no longer works because I didn't know the version was downgraded.

I would think the existing behavior should only be used if I specifically tell it I want a version greater than X or lower than Y, etc... If I tell you I want a compatible version between these 2 numbers (or between this version and the latest), then you should look for one, otherwise you should get only the version I specified or the latest if I didn't specify.

I don't think I've seen any dependency resolvers in other ecosystems doing this. We use exactly the same dependency resolver used by Pip and the downgrading behavior you describe is typically referred to as "backtracking" which was one of the primary reasons to refactor the old less robust resolver Pip used to have before that.
Normally, dependency resolvers are expected to output a dependency tree that is consistently non-conflicting across all the packages returned. So such a request seems weird to me.
Anyway, you could file a feature request for a CLI flag to facilitate this behavior, it'd have to be opt-in because it's not a normal expectations people have, from my experience with a lot of other packaging ecosystems. I can't guarantee that such an FR would be accepted, though.

@webknjaz
Copy link
Member

That is also what it seems the documentation implies will happen (* = latest).

No, "*" == "any", not latest.

@jborean93
Copy link
Contributor

Just an FYI the latest version isn’t always the highest version available. When testing all this when the client was developed the value showed the last uploaded version. This would be problematic with collections that might still be uploading versions. For example if 2.1.0 was published but then 2.0.1 was published after, the returned version here will he 2.0.1.

@sivel
Copy link
Member

sivel commented Sep 14, 2023

The highest/latest version may also report pre-releases in the API. Pre-releases as of now aren't filtered by the API.

@webknjaz
Copy link
Member

webknjaz commented Sep 14, 2023

Pre-releases as of now aren't filtered by the API.

I thought so but no, they are filtered on the depresolver side and this allowed me to make it more clever about collections that don't have stable versions: #81606

Ah.. nevermind. I can't read.

@sivel
Copy link
Member

sivel commented Sep 15, 2023

Ah.. nevermind. I can't read.

My bad, I wasn't specific about what API I was talking about. The galaxy web api 😀

@webknjaz
Copy link
Member

@s-hertel @sivel should this be closed with the explanation that the API's "latest" is not necessarily "highest version"? It doesn't seem there's anything actionable here. Not unless Galaxy starts tracking the highest version and exposing an extra endpoint for that...

@sivel
Copy link
Member

sivel commented Sep 26, 2023

As of now, there is nothing we can do here. galaxy_ng depends on pulp, and pulp is making additional changes to version sorting and latest in their code, and then potentially once that is completed, galaxy_ng would need to make changes on top of that. We've sped up install a lot in recent releases by no longer making API calls for every version, we only get a full list of versions, and only call the individual version API for the candidate we are going to install. We probably won't save much time by going down this route of consulting highest_version / latest, and it might restrict us later.

@tibeer
Copy link
Author

tibeer commented Sep 27, 2023

agreed :)

@tibeer tibeer closed this as completed Sep 27, 2023
@ansible ansible locked and limited conversation to collaborators Oct 11, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
affects_2.13 bug This issue/PR relates to a bug. P3 Priority 3 - Approved, No Time Limitation
Projects
None yet
Development

No branches or pull requests

8 participants