chocolatey / chocolatey-ansible

The Chocolatey module collection for Ansible
GNU General Public License v3.0
48 stars 30 forks source link

Collection version 1.2.0 breaks my ability to install chocolatey from a custom source. #74

Closed watsonb closed 2 years ago

watsonb commented 2 years ago

What You Are Seeing?

Version 1.2.0 of collection breaks my existing role that installs chocolatey from a custom source (on-prem Sonatype Nexus OSS caching proxy). Versions 1.0.2 and 1.1.0 work without any modification on my side.

What is Expected?

My custom Ansible role that installs chocolatey from a custom source still works when moving to collection version 1.2.0 as it did when using collection versions 1.0.2 and 1.1.0.

How Did You Get This To Happen? (Steps to Reproduce)

I tested a different role with molecule that leverages my custom chocolatey role (in molecule prepare) and did not pin the version of chocolatey.chocolatey collection. I saw the following error repeatedly:

fatal: [knemol-ar-win-java-2019-benlocal.example.com]: FAILED! => changed=false 
  msg: 'Failed to download Chocolatey script from ''http:/nexus.example.com:8081/repository/choco-all/install.ps1''; Exception calling "DownloadString" with "1" argument(s): "The given path''s format is not supported."'
  rc: 0

I think this stems from an improvement I saw in the 1.2.0 changlog:

Improved automatic URL handling for getting the install.ps1 script from a custom source URL

For now, I'll be looking at my custom chocolatey role to see what adjustments I can make to make it work with v1.2.0 of this collection and pin my other dependencies to 1.1.0.

The failing task in my custom role looks like this:

- name: WIN_CHOCOLATEY | install chocolatey
  chocolatey.chocolatey.win_chocolatey:
    name: chocolatey
    source: "{{ chocolatey_sources[0].source }}"
  environment:
    - chocolateyDownloadUrl: "{{ chocolatey_sources[0].source }}/{{ chocolatey_package_download_suffix }}"

And the task in my molecule prepare that applies the custom role looks like this:

    - name: apply win_chocolatey role
      ansible.builtin.import_role:
        name: ar_win_chocolatey
      vars:
        chocolatey_version: 0.10.15
        chocolatey_package_download_suffix: 'chocolatey/0.10.15'
        chocolatey_sources:
          - name: nexus
            source: http://nexus.example.com:8081/repository/choco-all/
            state: present
        chocolatey_features: []
        chocolatey_configs:
          - name: webRequestTimeoutSeconds
            state: present
            value: 45
        chocolatey_packages: []
        chocolatey_display_facts: false

System Details

N/A

Output Log

N/A

vexx32 commented 2 years ago

Thanks for the report! We'll have a look over the changes and look to see what went wrong there. At a glance, I can see you're looking to download chocolatey as a nupkg directly, which is not something the initial installation would normally do -- typically the bootstrapping installation downloads an install.ps1 file, similar to https://community.chocolatey.org/install.ps1, which then handles the actual getting of the nupkg and installing it.

I suspect this may have worked somewhat "by accident" in the past, the collection likely presumed it couldn't handle the URL, went to fetch the default install.ps1 from Chocolatey.org instead, and used that script to download the nupkg you'd supplied.

It's clear that we need to be more careful in our assumptions around the URL format. Perhaps we should simply have an additional parameter to find the install script for installing chocolatey itself rather than attempting to reuse source in this fashion. 🤔

For now, I think removing the source option from your playbook task would get you the pre-1.2.0 behaviour again. Even in earlier versions, source shouldn't do anything when applied to a chocolatey installation itself unless Chocolatey is already installed.

watsonb commented 2 years ago

Hmmm, I was afraid of that (i.e. it worked earlier due to a bug [unintended feature]). I started iterating over different URL paths and eventually got it to work with the 1.2.0 collection and my custom role unmodified. I merely had to pass a different URL.

For posterity:

  1. My Nexus server does offer up an install.ps1 script up at the root of the public resources (/opt/nexus-latest/public/install.ps1) that is then GETtable from https://nexus.example.com:8081/install.ps1
  2. My Nexus server is configured to host NuGet packages and cache/proxy them from chocolatey.org. http://nexus.example.com:8081/repository/choco-all/
  3. The chocolatey installer itself (the nupkg) is available at http://nexus.example.com:8081/repository/choco-all/chocolatey/0.10.15

So now my task that applies my custom role for installing/bootstrapping chocolatey looks like this:

    - name: apply win_chocolatey role
      ansible.builtin.import_role:
        name: ar_win_chocolatey
      vars:
        chocolatey_version: 0.10.15
        # chocolatey_package_download_suffix: 'chocolatey/0.10.15'
        # chocolatey_package_download_suffix: ''
        chocolatey_package_download_suffix: 'repository/choco-all/chocolatey/0.10.15'
        chocolatey_sources:
          - name: nexus
            # source: http://nexus.example.com:8081/repository/choco-all/
            source: http://nexus.example.com:8081
            state: present
        chocolatey_features: []
        chocolatey_configs:
          - name: webRequestTimeoutSeconds
            state: present
            value: 45
        chocolatey_packages: []
        chocolatey_display_facts: false

I left the commented out YAML bits in there so you could see how the URLs were changed as I experimented and found something that worked.

In short, it looks like the "source" is where to obtain the bootstrap install.ps1 and my "suffix" is appended to that as an environment variable to indicate where to get the nupkg.

vexx32 commented 2 years ago

Glad you could get it working! At least now we can be sure it's actually using the install.ps1 you have. 😄

Yeah, it's probably not ideal to have the source reused in this fashion to discover the install.ps1, and I think it's probably better to have a specific parameter to target the install.ps1 directly. I suppose we could add that on top of the logic we have, leaving the current logic as a fallback. 🤔

It certainly would make the behaviour more discoverable and easier to work with, I think. We should also add some docs to source indicating how this fallback behaviour actually works.

watsonb commented 2 years ago

Yeah, I'm running into other behavior issues now when managing sources pointing to my Nexus. Previous when I would add the source, the URL was http://nexus.example.com:8081/repository/choco-all/, which is the location of all cached packages. But by now specifying the root (for bootstrapping), I'd have to adjust the source when installing any other packages. I think I've found a way to work around it a little more elegantly for my use case (really just a variable data management issue).

Thanks for all the good work on this collection thus far! Using Ansible in a "Windows shop", I leverage this quite often.