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

Managed Conda runtime #218

Merged
merged 40 commits into from
Oct 5, 2022
Merged

Managed Conda runtime #218

merged 40 commits into from
Oct 5, 2022

Conversation

tsibley
Copy link
Member

@tsibley tsibley commented Sep 13, 2022

This uses the Conda/Mamba ecosystem for the runtime environment, but the user doesn't ever have to manage Conda themselves, thus potentially making it the easiest install option when paired with the standalone installer. The Docker runtime is still more isolated and robust, but I think this provides a really nice middle ground between "native" and Docker.

Context from Slack when I first started this work. There's a lot more in this PR because it turns out that while the basics of the runner/runtime itself was pretty straightforward to implement, there was a lot of complexity in how it integrated with the rest of Nextstrain CLI, parts of which previously had the historical luxury of assuming Docker-only. Many improvements were made there, some I'd noted as good-to-do long ago, so that's nice.

Related issue(s)

Related to #217.

Todo

  • setup --dry-run flag (ref)
  • setup should warn and offer guidance if no default is configured (ref)
  • Handle or avoid spaces in user data dir path
  • Add additional runtime checks that fail if we can't actually run programs in the env
  • setup --help should note acceptable <runtime> values
  • Testing plan
    • Manually on macOS Apple Silicon hardware
    • Manually on macOS Intel hardware
    • Manually on Linux
    • Manually on WSL (should be same, but good to check)
    • Manually on Windows (i.e. detection that it's unsupported works)
    • What else?
  • Isolation level question (i.e. PATH)
  • Final yea/nay on "managed Conda" name (decision: use "Conda")
  • Interaction with "native" runtimes with unmanaged Conda env; can we support both with this? (decision: don't broaden scope here, at least for now)
  • Rename "native" to "ambient" (decision: in new PR)
  • Documentation update (note to self: see your WIP for docs.nextstrain.org)

Testing

TKTK

@tsibley tsibley requested a review from a team September 13, 2022 22:35
@tsibley tsibley force-pushed the trs/managed-conda-runtime branch from dc0a6bc to 70b138c Compare September 13, 2022 22:43
@tsibley tsibley force-pushed the trs/managed-conda-runtime branch from 70b138c to 30accef Compare September 14, 2022 16:18
@tsibley
Copy link
Member Author

tsibley commented Sep 14, 2022

@tsibley tsibley force-pushed the trs/managed-conda-runtime branch 3 times, most recently from c11234a to 4ff7b15 Compare September 23, 2022 16:44
@corneliusroemer
Copy link
Member

corneliusroemer commented Sep 23, 2022

Testing this with:

mamba create -n managed-conda pip
conda activate managed-conda 
pip install -e .

on my M1 MBP.

It'd be great to have a list of accepted args for runtime:

❯ nextstrain setup -h
usage: nextstrain setup [-h] [--dry-run] [--force] [--set-default] <runtime>

Sets up a Nextstrain runtime for use with `nextstrain build`, `nextstrain view`,
etc.

Only the managed Conda runtime currently supports automated set up, but this
command may still be used with other runtimes to check an existing (manual)
setup and set the runtime as the default on success.

Exits with an error code if automated set up fails or if setup checks fail.

positional arguments:
  <runtime>      The Nextstrain build environment (aka Nextstrain runtime) to set up.

options:
  -h, --help     show this help message and exit
  --dry-run      Don't actually set up anything, just show what would happen. (default: False)
  --force        Ignore existing setup, if any, and always start fresh. (default: False)
  --set-default  Use the build environment (runtime) as the default if set up is successful. (default: False)

This only shows when you enter something invalid:

cli on  trs/managed-conda-runtime via 🐍 v3.10.6 via 🅒 managed-conda 
❯ nextstrain setup managed   
usage: nextstrain setup [-h] [--dry-run] [--force] [--set-default] <runtime>
nextstrain setup: error: argument <runtime>: invalid choice: 'managed' (choose from 'docker', 'managed-conda', 'native', 'aws-batch')

We can probably get rid of the r channel to speed things up a little. I never need r stuff.

pkgs/r/osx-64                                      820.9kB @ 340.6kB/s  0.5s
pkgs/r/noarch                                        1.3MB @ 477.0kB/s  0.6s

Seems to work out of the box :) Even on an M1, that's pretty amazing! Well done @tsibley

@corneliusroemer
Copy link
Member

When trying to run a workflow, I get the following weird error - no idea where this is from. We don't seem to have a --verbose option for the cli which comes to bite here. I'd like to know where exactly the error is thrown.

~/code via 🅒 managed-conda 
❯ nextstrain build .           
Error executing into ['snakemake', '--printshellcmds', '--cores=all']: [Errno 2] No such file or directory: b'/opt/homebrew/opt/fzf/bin/snakemake'

@tsibley
Copy link
Member Author

tsibley commented Sep 23, 2022

When trying to run a workflow, I get the following weird error - no idea where this is from.

You're running into the issue with spaces. I'll have a fix soon. Should have put this PR back into draft mode... but thanks for testing it out so far!

@tsibley tsibley marked this pull request as draft September 23, 2022 21:56
@tsibley
Copy link
Member Author

tsibley commented Sep 23, 2022

It'd be great to have a list of accepted args for runtime:

Yes, indeed. Will do!

We can probably get rid of the r channel to speed things up a little. I never need r stuff.

pkgs/r/osx-64                                      820.9kB @ 340.6kB/s  0.5s
pkgs/r/noarch                                        1.3MB @ 477.0kB/s  0.6s

Those come from the --channel defaults, which I left enabled because we do so elsewhere in Conda install instructions. I think we can disable the default channels entirely and use just conda-forge and bioconda, but I'm not sure without more testing and we can always do it later. In any case, including those R channels amounts to 1.1s of channel metadata download time (per your numbers above), but that's concurrent with the much larger conda-forge download time. So it doesn't reduce wall clock time there. It might reduce wall clock time of package resolution, but nextstrain setup managed-conda already seems quick enough to me that I'm not sure it's worth worrying over right out of the gate. :-)

@tsibley tsibley force-pushed the trs/managed-conda-runtime branch 5 times, most recently from eb80ff0 to 5ee825a Compare September 26, 2022 18:58
@tsibley
Copy link
Member Author

tsibley commented Sep 26, 2022

It'd be great to have a list of accepted args for runtime:

Yes, indeed. Will do!

Fixed in latest repush, along with a similar issue for update.

@tsibley tsibley force-pushed the trs/managed-conda-runtime branch from 5ee825a to 74f0113 Compare September 26, 2022 20:17
@tsibley tsibley marked this pull request as ready for review September 26, 2022 21:20
@tsibley tsibley requested a review from a team September 26, 2022 21:20
@tsibley
Copy link
Member Author

tsibley commented Sep 26, 2022

I think this work is ready to be merged. If folks who tested on macOS earlier and helped identify some issues could test again with the latest version in this PR, that'd be great. New folks testing would also be appreciated.

Outstanding questions/tasks that would be good to answer definitely/do before this is first released (even if not before this PR is merged):

  • Final yea/nay on "managed Conda" name. I don't love it, but don't have better ideas so it's what I'm going with unless others have better suggestions.
  • Changelog entries for all this stuff :-)
  • Update doc/installation.md to include this runtime

Other outstanding questions/tasks can (should be) be addressed after merge/release:

  • Rename "native" runtime/runner to "ambient" #224
  • Address commands available in Docker runtime that aren't in Conda runtime (ref)
  • Update docs.nextstrain.org install instructions to use this. I have a WIP, but it needs some more consideration of how the doc can simplify for new comers but not abandon previous users.
  • Moving standalone installer location to under ~/.nextstrain/ (done)

This reverts commits a5253b2 and
c598c4f.

These docs are no longer fetched into our main documentation repo as of
its f64d47e24a70729c235e8d7acc1f3802c5f08401 commit.
This isn't such a big deal.  It's more common to incorrectly add
placeholders to a string that's not already an f-string and forget to
add the "f".  A few more not-strictly-necessary f-strings in the
codebase may help avoid some of that! 🙃
tsibley added 23 commits October 5, 2022 16:05
By specifying --rcfile, the user's existing local interactive shell
config is ignored.  This more closely matches the non-interactive
`build` environment and avoids local shell config which may modify PATH,
provide aliases, etc.
…and the fallback default isn't what we just set up.

This catches a case where the --set-default option probably was
intended.  Flagged by @jameshadfield during review.
Lets folks see what will be downloaded, where it will go, etc. before
they actually do it.  A good suggestion by @jameshadfield in review.

Diff best viewed with whitespace ignored.
Nice to be crystal clear that what's said to be happening is not
_actually_ happening and make this consistent across commands with
dry run modes.

Providing this indication as an enterable context that doesn't require
changing subsequently-called code means that code doesn't have to be
muddied with conditional printing of indications.  While this wasn't
an issue for the existing dry run indications formerly used by the
`nextstrain remote` family of commands, it was a greater issue when
considering indications for the `nextstrain setup` command.  Thus this
work was motivated.

I used wrapt.ObjectProxy to implement LinePrefixer because a) it'll do a
*much* more thorough job of proxying than a basic __getattr__ override
and b) wrapt is already in our dep chain anyway. \o/
…mbol

This matters when sys.stderr is replaced (perhaps temporarily) by
another file object, such as with redirect_stderr() from contextlib or
even in our own __main__.py initialization.  Such replacement is a
common pattern.  Doing the module attribute lookup in warn() means it'll
be context-dependent, whereas importing the symbol meant we got whatever
the value was at import time.

Switches to sys.exit() too so we can remove the "from sys import …"
statement all together.
A hallmark of shells that we've been lacking!

Made a bit easier now with the prior changes to support the managed
Conda runtime.
…nd but runnable

This catches situations where an executable is installed but doesn't
actually work, which, for example, we observed in testing of the managed
Conda runtime when a space was in the prefix path.  This could also
happen other ways, and it's easy enough for us to verify these programs
actually run (at least superficially enough for --version to work).
While the per-platform user-specific application data dirs are a nice
idea and worked for our (current) standalone installation needs, part of
the point of using them was anticipation that we'd also put other app
data there, like the managed Conda runtime files.  This ideal would keep
a clean separation between app data in the platform-intended locations
and app config in ~/.nextstrain.

However, despite attempted workarounds, the platform-intended location
on macOS turned out be unusable for the managed Conda runtime because
"~/Library/Application Support" includes spaces.¹  So we ended up using
~/.nextstrain/runtimes for that.

Instead of splitting app data across multiple places, let's double down
and use ~/.nextstrain for everything.  ~/.nextstrain is already used
across platforms and is itself bespoke—it really should have been
platform-specific dirs like ~/.config or $XDG_CONFIG_HOME—so ISTM
there's little point following platform conventions for some things but
not others.

This commit takes no pains to have the installers consider previous
installations into the old paths since the installers are not yet
"released" in any sense, e.g. they're not a documented installation
method.  The only folks who should be impacted are the core team
members, and we can manually tidy our machines up as necessary.

¹ #218 (comment)
A single word is simpler and better parallels the name of the Docker
runtime, which is a) named after the technology it uses (the "engine")
and b) also "managed" but doesn't say so in its name.

I'd used "managed Conda" because "Conda" by itself seemed too confusing:
we've long recommended that folks use Conda to manually setup an
environment suitable for the "native" runner.  There's a strong
historical association there that we'd be tangling up users in.  The
simpler "Conda" name does feel like the better name in the long run,
though.  Our hope is that we can avoid a lot of this confusion by
renaming "native" → "ambient" (more accurate anyhow), rephrasing our
install docs, and adding an FAQ entry or two.  We'll undoubtedly still
deal with some.

A push for this renaming and votes of confidence were given by
@victorlin and @huddlej in Slack.¹

¹ <https://bedfordlab.slack.com/archives/C01LCTT7JNN/p1664232205090739?thread_ts=1662072691.294419&cid=C01LCTT7JNN>
Broadens the messaging in "setup: Warn the user if there's no default
runtime configured…" (171e4ee), again at the good suggestion of
@jameshadfield during further review.
…e function

Before we were standardizing its command-line arguments, but this now
standardizes how it's executed too.  That's important now as I want to
modify it's execution environment.
…amba

This avoids touching the ~/.mamba/ directory in the user's real homedir,
which is more than cosmetically important since installed files in
user-controlled Conda environments may be linked to the package cache
there.  We want to be able to invoke `micromamba clean` safely.

Note that HOME isn't set when running commands inside this runtime, only
during management operations with Micromamba.
Super handy for edit/preview cycles in dev.  Replaces a klunkier,
Linux-only homegrown alternative.
This was remote only because at the time it pointed to a non-merged
branch.  The AWS Batch doc page has since been included in the normal
Sphinx build.
Many users probably want to use our general Nextstrain installation
guide instead.
The biggest impact of this change is on Python 3.7 where we were seeing
CI test failures.¹  Those now pass again.  The story is complicated.
Let's start with the facts.

The recent release of importlib-metadata 5.0.0 removed a previously
deprecated entry points API.²

This API is used by flake8.

flake8 4.0.0 onwards declares (more or less):

    importlib-metadata <4.3; python_version < "3.8"

…while prior versions, flake8 3.9.2 and earlier, declared:

    importlib-metadata; python_version < "3.8"

Note that flake8 3.9.2 and earlier still require in practice the upper
bound on the importlib-metadata version, they just don't express it in
package metadata.  (This is what's known as foreshadowing…)

Meanwhile, Sphinx 4.4.0 onwards declares (more or less):

    importlib-metadata >=4.4; python_version < '3.10'

Note that on Python 3.7 and earlier, the latest versions of both flake8
and Sphinx have conflicting version requirements for importlib-metadata.

So when Pip on 3.7 goes to install both, it has to resolve the issue by
downgrading either flake8 or Sphinx until it finds a dependency
solution.  For whatever reason, it choose to keep the newer versions of
Sphinx and importlib-metadata and downgrade flake8.  So it walks back in
flake8 versions until it eventually finds 3.9.2 without the
importlib-metadata version pin.  Pip is satisfied, but although Pip
can't know it, flake8 won't work with importlib-metadata 5.0.0.

By pinning flake8 ≥4.0.0, we're hinting to Pip that only those versions
accurately declare their dependencies given the current situation.  Pip
ultimately can use this better dependency information solve the
importlib-metadata conflict by walking back to a version of Sphinx
≤4.4.0 (which it turns out, don't use importlib-metadata at all).

The flake8 breakage doesn't arise on Python 3.6 because support for that
Python version was dropped by importlib-metadata ≥4.9.0, so the removed
API in 5.0.0 isn't seen.  Without our flake8 pin, Pip still resolves the
conflict by walking flake8 back to 3.9.2 and keeping the latest Sphinx
plus importlib-metadata 4.8.3.  While that importlib-metadata version is
declared as unsupported in later version of flake8, it seems to work
fine in practice. ¯\_(ツ)_/¯

On Python ≥3.8, the importlib-metadata conflict doesn't exist,
presumably because flake8 uses the importlib.metadata standard library
instead.

We'll still build our production docs on RTD with the latest version of
Sphinx, because we use Python 3.10 there, and the downgrading of Sphinx
is limited to 3.7.

(If some of this is making your head ring but also ringing some bells,
this isn't the first time importlib-metadata's development choices and
flake8's development choices have had fallout for us.³)

¹ python/importlib_metadata#409 (comment)
² python/importlib_metadata#405
³ "dev: Ignore a deprecation warning generated by flake8's usage of importlib_metadata" (1a04901)
See <ryanfox/sphinx-markdown-tables#38>.

With the downgrade of Sphinx on 3.6 and 3.7 caused by "dev: Require
flake8 ≥4.0.0" (352b8d7), this incorrect dep declaration was causing
issues because Pip thought things were compatible when in reality the
docs build didn't work on those Python versions.
@tsibley tsibley force-pushed the trs/managed-conda-runtime branch from f1bbe00 to 221a2ae Compare October 5, 2022 23:09
@tsibley
Copy link
Member Author

tsibley commented Oct 5, 2022

Repushed to reword the outdated commit message of ef61e86, now 6e2d73d, which I noticed while changelog writing.

@tsibley tsibley merged commit bfe3b0b into master Oct 5, 2022
@tsibley tsibley deleted the trs/managed-conda-runtime branch October 5, 2022 23:10
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.

4 participants