TL;DR: env was Fabric 1's global settings bag; Fabric 2 has no equivalent. Move host lists into explicit Connection objects and settings into fabric.Config, or pin fabric<2 for the legacy fabfile.

```text
ImportError: cannot import name 'env' from 'fabric.api'
```

## Fix it

1. Replace env.hosts loops with explicit connections: for h in hosts: Connection(h).run(cmd). Expected: runs on each host.
2. Replace env.password / env.key_filename with connect_kwargs={'password': [your password]} or connect_kwargs={'key_filename': [path]}. Expected: auth works per connection.
3. Replace env.warn_only with Config(overrides={'run': {'warn': True}}). Expected: non-fatal failures as before.
4. Or pin fabric<2 to defer the rewrite. Expected: legacy fabfile runs.

## When this applies
- The code does from fabric.api import env (or uses env.*) on fabric 2+.

## When it doesn't
- fabric is 1.x: env exists; reinstall if the import fails.
- You are on the new API already: check for a typo.

## Compatibility
- Fabric 1.x vs 2.x/3.x.

## Why it happens
The v2 rewrite replaced global mutable state (env) with explicit per-connection configuration, which is saner but breaks every 1.x fabfile that touched env.

## Edge cases
- env.roledefs has no direct equivalent; build host lists in plain Python.
- Serial vs parallel execution is now controlled by the Executor, not env.parallel.
