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

[update] Allow downgrades during nextstrain update conda #266

Merged
merged 7 commits into from
Mar 24, 2023

Conversation

tsibley
Copy link
Member

@tsibley tsibley commented Mar 15, 2023

See commit messages.

Related issue(s)

#264

Testing

@tsibley tsibley changed the title [update];runner.conda: Allow downgrades during update of nextstrain-base [update] Allow downgrades during nextstrain update conda Mar 15, 2023
@tsibley
Copy link
Member Author

tsibley commented Mar 15, 2023

Hmm. This worked for my fresh reproduction of the issue in #264 in another NEXTSTRAIN_RUNTIMES location. But it's seemingly not sufficient for my default runtime location where I'd also happened to observe the same issue as @corneliusroemer. Not sure what's going on yet.

@tsibley
Copy link
Member Author

tsibley commented Mar 15, 2023

Ok, it's running into some other conflict that it can't/won't resolve under the current conditions, and so "solves" the update request as a no-op.

info     libsolv  resolving job rules
info     libsolv  resolving installed packages
info     libsolv  prune_to_best_version_conda 18
info     libsolv  - nextstrain-base-20230208T180335Z-hb0f4dca_1_locked [564898]I
info     libsolv  - nextstrain-base-20221109T175138Z-hb0f4dca_1_locked [2]
info     libsolv  - nextstrain-base-20230122T012621Z-hb0f4dca_1_locked [4]
info     libsolv  - nextstrain-base-20221215T210429Z-hb0f4dca_1_locked [5]
info     libsolv  - nextstrain-base-20221222T192357Z-hb0f4dca_1_locked [6]
info     libsolv  - nextstrain-base-20230208T180335Z-hb0f4dca_1_locked [7]
info     libsolv  - nextstrain-base-20230303T182321Z-hb0f4dca_1_locked [8]
info     libsolv  - nextstrain-base-20230221T204043Z-hb0f4dca_1_locked [9]
info     libsolv  - nextstrain-base-20230308T220440Z-hb0f4dca_1_locked [10]
info     libsolv  - nextstrain-base-20230228T182057Z-hb0f4dca_1_locked [11]
info     libsolv  - nextstrain-base-20221208T010248Z-hb0f4dca_1_locked [12]
info     libsolv  - nextstrain-base-20221214T200025Z-hb0f4dca_1_locked [13]
info     libsolv  - nextstrain-base-20230314T174809Z-hb0f4dca_1_locked [14]
info     libsolv  - nextstrain-base-20221019T172207Z-hb0f4dca_1_locked [15]
info     libsolv  - nextstrain-base-20230119T175438Z-hb0f4dca_1_locked [16]
info     libsolv  - nextstrain-base-20221208T010417Z-hb0f4dca_1_locked [17]
info     libsolv  - nextstrain-base-20221209T222639Z-hb0f4dca_1_locked [19]
info     libsolv  - nextstrain-base-20230221T201501Z-hb0f4dca_1_locked [20]
info     libsolv  installing nextstrain-base-20230314T174809Z-hb0f4dca_1_locked
info     libsolv  conflict with rule #17643951
info     libsolv  ANALYZE at 2 ----------------------
info     libsolv  UPDATE Rule #17643951:
info     libsolv      libjpeg-turbo-2.1.4-h166bdaf_0 [564861]I (w1) Conflict.level2
info     libsolv      libjpeg-turbo-1.5.1-0 [129143] (w2) Conflict.level2
info     libsolv      libjpeg-turbo-1.5.2-0 [129144] Conflict.level2
info     libsolv      libjpeg-turbo-1.5.3-0 [129145] Conflict.level2
info     libsolv      libjpeg-turbo-1.5.90-0 [129146] Conflict.level2
info     libsolv      libjpeg-turbo-2.0.0-h14c3975_1000 [129147] Conflict.level2
info     libsolv      libjpeg-turbo-2.0.0-h470a237_0 [129148] Conflict.level2
info     libsolv      libjpeg-turbo-2.0.1-h14c3975_1000 [129149] Conflict.level2
info     libsolv      libjpeg-turbo-2.0.1-h470a237_0 [129150] Conflict.level2
info     libsolv      libjpeg-turbo-2.0.2-h14c3975_0 [129151] Conflict.level2
info     libsolv      libjpeg-turbo-2.0.3-h516909a_0 [129152] Conflict.level2
info     libsolv      libjpeg-turbo-2.0.3-h516909a_1 [129153] Conflict.level2
info     libsolv      libjpeg-turbo-2.0.5-h516909a_0 [129154] Conflict.level2
info     libsolv      libjpeg-turbo-2.0.5-h7f98852_0 [129155] Conflict.level2
info     libsolv      libjpeg-turbo-2.1.0-h7f98852_0 [129156] Conflict.level2
info     libsolv      libjpeg-turbo-2.1.1-h7f98852_0 [129157] Conflict.level2
info     libsolv      libjpeg-turbo-2.1.3-h166bdaf_0 [129158] Conflict.level2
info     libsolv      libjpeg-turbo-2.1.4-h166bdaf_0 [129159] Conflict.level2
info     libsolv      libjpeg-turbo-2.1.4-h0b41bf4_1 [329637] Conflict.level2
info     libsolv      libjpeg-turbo-2.1.5.1-h0b41bf4_0 [329638] Conflict.level2
info     libsolv      next rules: 0 0
info     libsolv  Rule #2641001:
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w1) Install.level2
info     libsolv      !libjpeg-turbo-1.5.1-0 [129143] (w2) Conflict.level2
info     libsolv      next rules: 2641002 6925480
info     libsolv  Rule #2641000:
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w1) Install.level2
info     libsolv      !libjpeg-turbo-1.5.2-0 [129144] (w2) Conflict.level2
info     libsolv      next rules: 2641001 6925479
info     libsolv  Rule #2640999:
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w1) Install.level2
info     libsolv      !libjpeg-turbo-1.5.3-0 [129145] (w2) Conflict.level2
info     libsolv      next rules: 2641000 6925478
info     libsolv  Rule #2640998:
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w1) Install.level2
info     libsolv      !libjpeg-turbo-1.5.90-0 [129146] (w2) Conflict.level2
info     libsolv      next rules: 2640999 6925477
info     libsolv  Rule #2640997:
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w1) Install.level2
info     libsolv      !libjpeg-turbo-2.0.0-h14c3975_1000 [129147] (w2) Conflict.level2
info     libsolv      next rules: 2640998 6925476
info     libsolv  Rule #2640996:
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w1) Install.level2
info     libsolv      !libjpeg-turbo-2.0.0-h470a237_0 [129148] (w2) Conflict.level2
info     libsolv      next rules: 2640997 6925475
info     libsolv  Rule #2640995:
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w1) Install.level2
info     libsolv      !libjpeg-turbo-2.0.1-h14c3975_1000 [129149] (w2) Conflict.level2
info     libsolv      next rules: 2640996 6925474
info     libsolv  Rule #2640994:
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w1) Install.level2
info     libsolv      !libjpeg-turbo-2.0.1-h470a237_0 [129150] (w2) Conflict.level2
info     libsolv      next rules: 2640995 6925473
info     libsolv  Rule #2640993:
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w1) Install.level2
info     libsolv      !libjpeg-turbo-2.0.2-h14c3975_0 [129151] (w2) Conflict.level2
info     libsolv      next rules: 2640994 6925472
info     libsolv  Rule #2640992:
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w1) Install.level2
info     libsolv      !libjpeg-turbo-2.0.3-h516909a_0 [129152] (w2) Conflict.level2
info     libsolv      next rules: 2640993 6925471
info     libsolv  Rule #2640991:
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w1) Install.level2
info     libsolv      !libjpeg-turbo-2.0.3-h516909a_1 [129153] (w2) Conflict.level2
info     libsolv      next rules: 2640992 6925470
info     libsolv  Rule #2640990:
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w1) Install.level2
info     libsolv      !libjpeg-turbo-2.0.5-h516909a_0 [129154] (w2) Conflict.level2
info     libsolv      next rules: 2640991 6925469
info     libsolv  Rule #2640989:
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w1) Install.level2
info     libsolv      !libjpeg-turbo-2.0.5-h7f98852_0 [129155] (w2) Conflict.level2
info     libsolv      next rules: 2640990 6925468
info     libsolv  Rule #2640988:
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w1) Install.level2
info     libsolv      !libjpeg-turbo-2.1.0-h7f98852_0 [129156] (w2) Conflict.level2
info     libsolv      next rules: 2640989 6925467
info     libsolv  Rule #2640987:
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w1) Install.level2
info     libsolv      !libjpeg-turbo-2.1.1-h7f98852_0 [129157] (w2) Conflict.level2
info     libsolv      next rules: 2640988 6925466
info     libsolv  Rule #2640986:
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w1) Install.level2
info     libsolv      !libjpeg-turbo-2.1.3-h166bdaf_0 [129158] (w2) Conflict.level2
info     libsolv      next rules: 2640987 6925465
info     libsolv  Rule #2640985:
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w1) Install.level2
info     libsolv      !libjpeg-turbo-2.1.4-h166bdaf_0 [129159] (w2) Conflict.level2
info     libsolv      next rules: 2640986 6925465
info     libsolv  Rule #2629460:
info     libsolv      !libjpeg-turbo-2.1.4-h0b41bf4_1 [329637] (w1) Conflict.level2
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w2) Install.level2
info     libsolv      next rules: 2629461 2640985
info     libsolv  Rule #2629433:
info     libsolv      !libjpeg-turbo-2.1.5.1-h0b41bf4_0 [329638] (w1) Conflict.level2
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w2) Install.level2
info     libsolv      next rules: 2629434 2629460
info     libsolv  Rule #21721:
info     libsolv      !libjpeg-turbo-2.1.4-h166bdaf_0 [564861]I (w1) Conflict.level2
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w2) Install.level2
info     libsolv      next rules: 21722 24601
info     libsolv  learned rule for level 1 (am 2)
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] Install.level2
info     libsolv  reverting decisions (level 2 -> 1)
info     libsolv  decision:     !jpeg-9e-h0b41bf4_3 [328572] Conflict.level1
info     libsolv  new rule: Rule #17644277:
info     libsolv      !jpeg-9e-h0b41bf4_3 [328572] (w1) Conflict.level1
info     libsolv      next rules: 0 0
info     libsolv  prune_to_best_version_conda 12
info     libsolv  - nextstrain-base-20230208T180335Z-hb0f4dca_1_locked [564898]I
info     libsolv  - nextstrain-base-20221109T175138Z-hb0f4dca_1_locked [2]
info     libsolv  - nextstrain-base-20230122T012621Z-hb0f4dca_1_locked [4]
info     libsolv  - nextstrain-base-20221215T210429Z-hb0f4dca_1_locked [5]
info     libsolv  - nextstrain-base-20221222T192357Z-hb0f4dca_1_locked [6]
info     libsolv  - nextstrain-base-20230208T180335Z-hb0f4dca_1_locked [7]
info     libsolv  - nextstrain-base-20221208T010248Z-hb0f4dca_1_locked [12]
info     libsolv  - nextstrain-base-20221214T200025Z-hb0f4dca_1_locked [13]
info     libsolv  - nextstrain-base-20221019T172207Z-hb0f4dca_1_locked [15]
info     libsolv  - nextstrain-base-20230119T175438Z-hb0f4dca_1_locked [16]
info     libsolv  - nextstrain-base-20221208T010417Z-hb0f4dca_1_locked [17]
info     libsolv  - nextstrain-base-20221209T222639Z-hb0f4dca_1_locked [19]
info     libsolv  Fallback to timestamp comparison: 0 vs 1675879564: [1]
info     libsolv  Selecting variant [b] of (a) nextstrain-base-20230208T180335Z-hb0f4dca_1_locked vs (b) nextstrain-base-20230208T180335Z-hb0f4dca_1_locked (score: 1)
info     libsolv  creating a branch [data=17643988]:
info     libsolv    - nextstrain-base-20230208T180335Z-hb0f4dca_1_locked
info     libsolv    - nextstrain-base-20230208T180335Z-hb0f4dca_1_locked
info     libsolv  installing nextstrain-base-20230208T180335Z-hb0f4dca_1_locked
info     libsolv  keeping _libgcc_mutex-0.1-conda_forge
info     libsolv  keeping _openmp_mutex-4.5-2_gnu
info     libsolv  keeping aioeasywebdav-2.4.0-pyha770c72_0
info     libsolv  keeping aiohttp-3.8.3-py310h5764c6d_1
info     libsolv  keeping aiosignal-1.3.1-pyhd8ed1ab_0
info     libsolv  keeping appdirs-1.4.4-pyh9f0ad1d_0
[more "keeping …" lines enumerating all the already-installed explicit deps of the current nextstrain-base version]

To resolve this in the way we want, it needs to uninstall libjpeg-turbo-2.1.4-h166bdaf_0 (required by 20230208T180335Z) and replace it with nothing (its omitted from 20230314T174809Z), but it's not finding that solution or at least not deeming it acceptable. Even with the --allow-uninstall option explicitly given, which I tried but didn't expect to make a difference since it is documented to be enabled by default.

Two thoughts:

  1. There are nice reasons to perform an update operation (mainly, reuse existing packages, so its incremental and faster), but maybe what we should be doing instead is uninstall + install. It might be more in line with the outcome we prefer.
  2. Or, maybe we can hint to the update operation that we really do prefer a new version of nextstrain-base when one's available by using the package spec nextstrain-base >$CURRENT_VERSION instead of just nextstrain-base.

@tsibley
Copy link
Member Author

tsibley commented Mar 15, 2023

It looks like (2) will work.

@corneliusroemer
Copy link
Member

Why not ask it to install the most recent version directly rather than any version that's later than current?

IIUC, mamba/conda keeps packages around even after uninstall, so an uninstall, reinstall should be almost as cheap as update. But maybe this doesn't apply to micromamba.

@tsibley
Copy link
Member Author

tsibley commented Mar 16, 2023

Why not ask it to install the most recent version directly rather than any version that's later than current?

That's what we do for our Docker runtime, but I avoided it for Conda because it requires determining the latest version first and that can potentially be problematic to do correctly given that the way packages are platform-specific (differently than Docker's are). It seemed easier to just let Micromamba handle it. But I guess doing it ourselves ends up being about the same as what the Conda runner already does to download Micromamba when setting up the runtime.

So yeah, maybe I'll do that.

IIUC, mamba/conda keeps packages around even after uninstall, so an uninstall, reinstall should be almost as cheap as update. But maybe this doesn't apply to micromamba.

It does apply to Micromamba, but even without redownload, reinstall won't be as cheap as update due to the unlink/relinking cycle. It's also nice to show the diff of versions on update.

@tsibley
Copy link
Member Author

tsibley commented Mar 17, 2023

So yeah, maybe I'll do that.

To do this (or also my previous inclination) properly required a bit more change than it seemed at first, but I have a nice and robust solution now. Need to clean it up a bit and push additional commits to this PR, but will save that for next week.

tsibley added 6 commits March 20, 2023 17:11
This permits Micromamba to downgrade packages that are already installed
in order to upgrade nextstrain-base.  While nextstrain-base's
fully-locked dependencies from version to version will typically only
cause upgrades, there are times when downgrades may be required.¹  When
that's the case, Micromamba simply won't consider that nextstrain-base
version as available without --allow-downgrade.

Resolves <#264>.

¹ For example, the deps of Nextstrain CLI's package in Bioconda changed
  to better match its deps in PyPI², which meant versions of botocore,
  boto3, and some related packages had to be downgraded.

² <bioconda/bioconda-recipes#39711>
Not just after setup.  This ensures we remove older versions of
now-upgraded packages so they don't keep taking up disk space
unnecessarily.
…age distribution

I'm about to want to do the same query for our nextstrain-base package
to facilitate better update behaviour.
…versions

Consistent with the rest of the runner, which uses a package name
overridable by an environment variable.
…ONDA_BASE_PACKAGE

Previously you could smuggle a package match spec (e.g. ==X) into
NEXTSTRAIN_CONDA_BASE_PACKAGE because setup() and update() simply passed
it thru to Micromamba.  We even took advantage of this in the testing
instructions produced by our conda-base CI.¹

As I started to add more logic in update() and not just pass thru the
package name, I realized this version smuggling use case would pose an
issue and the code needed the values to be more predictable.  I didn't
want to remove the ability to specify a version spec though, nor parse
the ambiguous and (seemingly) not fully-specified `conda install`-style
specs, so I settled on properly supporting the more formal two- and
three-part Conda package match specs.²

This commit plumbs support for those thru the places which previously
assumed to take just a package name.

Note that this env var is still considered for development and testing
only, so this change shouldn't have any user-visible impact.

¹ <https://github.com/nextstrain/conda-base/blob/b8b9ca82/.github/workflows/ci.release.md>
² <https://docs.conda.io/projects/conda/en/latest/user-guide/concepts/pkg-specs.html#package-match-specifications>
This helps Micromamba (or really, libsolv) take the action we want,
upgrading to the latest version, as otherwise it sometimes chooses a
solution that results in no upgrade.¹

It's also good to be explicit about the version we expect, and this
behaviour is closer to what we do when updating other runtimes as well.
The update messaging is also improved in the no-op case by having the
desired version on hand.

¹ e.g. <#266 (comment)>
@tsibley tsibley force-pushed the trs/conda/update/allow-downgrades branch from 00757de to d6e4f2b Compare March 21, 2023 17:59
@tsibley
Copy link
Member Author

tsibley commented Mar 21, 2023

Repushed with additional fixes.

@tsibley tsibley requested review from a team and corneliusroemer March 21, 2023 21:59
@tsibley
Copy link
Member Author

tsibley commented Mar 21, 2023

If folks want to test this locally, one way is to use the standalone build for this PR:

curl -fsSL --proto '=https' https://nextstrain.org/cli/installer/linux \
  | DESTINATION=/tmp/nextstrain-cli bash -s pr-build/266

/tmp/nextstrain-cli/nextstrain update conda

tsibley added a commit to nextstrain/conda-base that referenced this pull request Mar 21, 2023
…A_BASE_PACKAGE

Per <nextstrain/cli#266>.  Applying in advance
of that Nextstrain CLI change, which should be safe as both package
specs should be accepted by Micromamba.
Copy link
Member

@victorlin victorlin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skimmed through the changes and tested locally:

  1. My current Conda runtime version is 20221019T172207Z.

    % nextstrain version --verbose | grep -F "nextstrain-base"
    Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
        nextstrain-base 20221019T172207Z (h0dc7051_1_locked, nextstrain)
    
  2. The latest available version is 20230314T174809Z.

    % CONDA_SUBDIR=osx-64 conda search --override-channels -c nextstrain nextstrain-base | tail -n 1
    nextstrain-base      20230314T174809Z h0dc7051_1_locked  nextstrain   
    
  3. CLI 6.2.0 updates to 20230303T182321Z.

    % nextstrain version
    nextstrain.cli 6.2.0
    % nextstrain update conda
      - nextstrain-base           20221019T172207Z  h0dc7051_1_locked    nextstrain               9kB
      + nextstrain-base           20230303T182321Z  h0dc7051_1_locked    nextstrain/osx-64        9kB
    
  4. CLI from this PR updates to 20230314T174809Z.

    % /tmp/nextstrain-cli/nextstrain version
    nextstrain.cli 6.2.0+git.f3b209b
    % /tmp/nextstrain-cli/nextstrain update conda
      - nextstrain-base    20230303T182321Z  h0dc7051_1_locked    nextstrain             Cached
      + nextstrain-base    20230314T174809Z  h0dc7051_1_locked    nextstrain/osx-64         9kB
    

@tsibley
Copy link
Member Author

tsibley commented Mar 24, 2023

@victorlin Awesome, that's exactly the sort of confirmation I was hoping to see from others. 🙌 Thanks! 🙏

@tsibley tsibley merged commit 6aa55f0 into master Mar 24, 2023
@tsibley tsibley deleted the trs/conda/update/allow-downgrades branch March 24, 2023 17:51
@corneliusroemer
Copy link
Member

Can confirm this works in production :)

image

@corneliusroemer
Copy link
Member

It is weird though that we suggest to install nextstrain-cli 6.2.0 🙃

@tsibley
Copy link
Member Author

tsibley commented Mar 29, 2023

It is weird though that we suggest to install nextstrain-cli 6.2.0 🙃

Ha. A little, yeah.

It'd be possible to mount a standalone installation of Nextstrain CLI into the runtime so the exact same version outside the runtime vs. inside the runtime is used. But for other installation methods it wouldn't be. So it seems easiest/simplest/best to not try to use the same installation inside and outside the runtime.

The point of having it in the runtime is mostly for simple invocations of the nextstrain remote family of commands (e.g. for deployment), so the hope is that the version in the runtime doesn't matter as much as if the full set of commands were in use.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

3 participants