Upgrading from 1.x¶
Modern Fabric (2+) represents a near-total reimplementation & reorganization of the software. It’s been broken in two, cleaned up, made more explicit, and so forth. In some cases, upgrading requires only basic search & replace; in others, more work is needed.
If you read this document carefully, it should guide you in the right direction until you’re fully upgraded. If any functionality you’re using in Fabric 1 isn’t listed here, please file a ticket on Github and we’ll update it ASAP.
Warning
As of the 2.0 release line, Fabric 2 is not at 100% feature parity with 1.x! Some features have been explicitly dropped, but others simply have not been ported over yet, either due to time constraints or because said features need to be re-examined in a modern context.
Please review the information below, including the Upgrade specifics section which contains a very detailed list, before filing bug reports!
Also see the roadmap for additional notes about release versioning.
Why upgrade?¶
We’d like to call out, in no particular order, some specific improvements in modern Fabric that might make upgrading worth your time.
Note
These are all listed in the rest of the doc too, so if you’re already sold, just skip there.
Thread-safe - no more requirement on multiprocessing for concurrency;
API reorganized around
fabric.connection.Connection
objects instead of global module state;Command-line parser overhauled to allow for regular GNU/POSIX style flags and options on a per-task basis (no more
fab mytask:weird=custom,arg=format
);Task organization is more explicit and flexible / has less ‘magic’;
Tasks can declare other tasks to always be run before or after themselves;
Configuration massively expanded to allow for multiple config files & formats, env vars, per-user/project/module configs, and much more;
SSH config file loading enabled by default & has been fleshed out re: system/user/runtime file selection;
Shell command execution API consistent across local and remote method calls - no more differentiation between
local
andrun
(besides where the command runs, of course!);Shell commands significantly more flexible re: interactive behavior, simultaneous capture & display (now applies to local subprocesses, not just remote), encoding control, and auto-responding;
Use of Paramiko’s APIs for the SSH layer much more transparent - e.g.
fabric.connection.Connection
allows control over the kwargs given toSSHClient.connect
;Gateway/jump-host functionality offers a
ProxyJump
style ‘native’ (no proxy-command subprocesses) option, which can be nested infinitely;
‘Sidegrading’ to Invoke¶
We linked to a note about this above, but to be explicit: modern Fabric is really a few separate libraries, and anything not strictly SSH or network related has been split out into the Invoke project.
This means that if you’re in the group of users leveraging Fabric solely for
its task execution or local
, and never used run
, put
or
similar - you don’t need to use Fabric itself anymore and can simply
‘sidegrade’ to Invoke instead.
You’ll still want to read over this document to get a sense of how things have
changed, but be aware that you can get away with pip install invoke
and
won’t need Fabric, Paramiko, cryptography dependencies, or anything else.
Using modern Fabric from within Invoke¶
We intend to enhance modern Fabric until it encompasses the bulk of Fabric 1’s
use cases, such that you can use fab
and fabfiles on their own without
caring too much about how it’s built on top of Invoke.
However, prior to that point – and very useful on its own for intermediate-to-advanced users – is the fact that modern Fabric is designed with library or direct API use in mind. It’s entirely possible, and in some cases preferable, to use Invoke for your CLI needs and Fabric as a pure API within your Invoke tasks.
In other words, you can eschew fab
/fabfiles entirely unless you find
yourself strongly needing the conveniences it wraps around ad-hoc sessions,
such as --hosts
and the like.
Running both Fabric versions simultaneously¶
To help with gradual upgrades, modern Fabric may be installed under the name
fabric2
(in addition to being made available “normally” as versions 2.0+ of
fabric
) and can live alongside installations of version 1.x.
Thus, if you have a large codebase and don’t want to make the jump to modern
versions in one leap, it’s possible to have both Fabric 1 (fabric
, as you
presumably had it installed previously) and modern Fabric (as fabric2
)
resident in your Python environment simultaneously.
Note
We strongly recommend that you eventually migrate all code using Fabric 1,
to versions 2 or above, so that you can move back to installing and
importing under the fabric
name. fabric2
as a distinct package and
module is intended to be a stopgap, and there will not be any fabric3
or above (not least because some of those names are already taken!)
For details on how to obtain the fabric2
version of the package, see
Installing modern Fabric as fabric2.
Creating Connection
and/or Config
objects from v1 settings¶
A common tactic when upgrading piecemeal is to generate modern Fabric objects
whose contents match the current Fabric 1 environment. Whereas Fabric 1 stores
all configuration (including the “current host”) in a single place – the
env
object – modern Fabric breaks things up into multiple (albeit
composed) objects: Connection
for per-connection
parameters, and Config
for general settings and defaults.
In most cases, you’ll only need to generate a Connection
object using the alternate class constructor Connection.from_v1
, which should be fed your appropriate
local fabric.api.env
object; see its API docs for details.
A contrived example:
from fabric.api import env, run
from fabric2 import Connection
env.host_string = "admin@myserver"
run("whoami") # v1
cxn = Connection.from_v1(env)
cxn.run("whoami") # v2+
By default, this constructor calls another API member – Config.from_v1
– internally on your behalf. Users who need
tighter control over modern-style config options may opt to call that
classmethod explicitly and hand their modified result into Connection.from_v1
, which will cause the latter to skip
any implicit config creation.
Mapping of v1 env
vars to modern API members¶
The env
vars and how they map to Connection
arguments
or Config
values (when fed into the .from_v1
constructors
described above) are listed below.
v1 |
v2+ usage (prefixed with the class it ends up in) |
---|---|
|
Config: |
|
Config: |
|
Config: |
|
Config: |
|
Connection: |
|
Not supported: Fabric 1 performed extra processing on this (trying a bunch of key classes to instantiate) before handing it into Paramiko; modern Fabric prefers to just let you handle Paramiko-level parameters directly. If you’re filling your Fabric 1 If you’re loading key data from some other source as a string, you
should know what type of key your data is and manually instantiate it
instead, then supply it to the from io import StringIO
from fabric.state import env
from fabric2 import Connection
from paramiko import RSAKey
from somewhere import load_my_key_string
pkey = RSAKey.from_private_key(StringIO(load_my_key_string()))
cxn = Connection.from_v1(env, connect_kwargs={"pkey": pkey})
|
|
Config: |
|
Config: |
|
Config: |
|
Connection: Note Since v1’s |
|
Config: |
|
Config: |
|
Config: |
|
Config: |
|
Config: |
|
Connection: |
|
Config: |
Upgrade specifics¶
This is (intended to be) an exhaustive list of all Fabric 1.x functionality, as well as new-to-Invoke-or-Fabric-2 functionality not present in 1.x; it specifies whether upgrading is necessary, how to upgrade if so, and tracks features which haven’t been implemented in modern versions yet.
Most sections are broken down in table form, as follows:
Fabric 1 feature or behavior |
Status, see below for breakdown |
Migration notes, removal rationale, etc |
Below are the typical values for the ‘status’ column, though some of them are a bit loose - make sure to read the notes column in all cases! Also note that things are not ironclad - eg any ‘removed’ item has some chance of returning if enough users request it or use cases are made that workarounds are insufficient.
Ported: available already, possibly renamed or moved (frequently, moved into the Invoke codebase.)
Pending: would fit, but has not yet been ported, good candidate for a patch. These entries link to the appropriate Github ticket - please do not make new ones!
Removed: explicitly not ported (no longer fits with vision, had too poor a maintenance-to-value ratio, etc) and unlikely to be reinstated.
Here’s a quick local table of contents for navigation purposes:
General / conceptual¶
The CLI task-oriented workflow remains a primary design goal, but the library use case is no longer a second-class citizen; instead, the library functionality has been designed first, with the CLI/task features built on top of it.
Additionally, within the CLI use case, version 1 placed too much emphasis on ‘lazy’ interactive prompts for authentication secrets or even connection parameters, driven in part by a lack of strong configuration mechanisms. Over time it became clear this wasn’t worth the tradeoffs of having confusing noninteractive behavior and difficult debugging/testing procedures.
Modern Fabric takes an arguably cleaner approach (based on functionality added to v1 over time) where users are encouraged to leverage the configuration system and/or serve the user prompts for runtime secrets at the start of the process; if the system determines it’s missing information partway through, it raises exceptions instead of prompting.
Invoke’s design includes explicit user-facing testing functionality; if you didn’t find a way to write tests for your Fabric-using code before, it should be much easier now.
We recommend trying to write tests early on; they will help clarify the upgrade process for you & also make the process safer!
API organization¶
High level code flow and API member concerns.
Import everything via |
Removed |
All useful imports are now available at the top level, e.g. |
Configure connection parameters globally (via |
Removed |
The primary API is now properly OOP: instantiate
See also |
Emphasis on serialized “host strings” as method of setting user, host, port, etc |
Ported/Removed |
Additionally, many arguments/settings/etc that expected a host string
in v1 will now expect a |
Use of “roles” as global named lists of host strings |
Ported |
This need is now served by See the line items for |
Task functions & decorators¶
Note
Nearly all task-related functionality is implemented in Invoke; for more details see its execution and namespaces documentation.
By default, tasks are loaded from a |
Ported |
This behavior is basically identical today, with minor modifications and enhancements (such as tighter control over the load process, and API hooks for implementing custom loader logic - see Loading collections.) |
“Classic” style implicit task functions lacking a |
Removed |
These were on the way out even in v1, and arbitrary task/namespace
creation is more explicitly documented now, via Invoke’s
|
“New” style |
Ported |
Largely the same, though now with superpowers - |
Arbitrary task function arguments (i.e. |
Ported |
This gets its own line item because: tasks must now take a
This sacrifices a small bit of the “quick DSL” of v1 in exchange for a cleaner, easier to understand/debug, and more user-overrideable API structure. As a side effect, it lessens the distinction between “module of functions” and “class of methods”; users can more easily start with the former and migrate to the latter when their needs grow/change. |
Implicit task tree generation via import-crawling |
Ported/Removed |
Namespace construction is now more explicit; for example, imported
modules in your However, the root We may reinstate (in an opt-in fashion) imported module scanning later, since the use of explicit namespace objects still allows users control over the tree that results. |
|
Ported |
Reinstated as the |
|
Pending |
See API organization for details on the overall ‘roles’ concept.
When it returns, this will probably follow |
|
Ported/Pending |
Parallel execution is currently offered at the API level via
The problem needs solving at a higher level than just SSH targets, so this links to an Invoke-level ticket. |
|
This is one of the top “missing features” from the rewrite; link is to Invoke’s tracker. |
|
|
Ported |
While not sharing many implementation details with v1, modern Fabric
(via Invoke) has a publicly exposed |
CLI arguments, options and behavior¶
Exposure of task arguments as custom colon/comma delimited CLI
arguments, e.g. |
Removed |
CLI arguments are now proper GNU/POSIX-style long and short flags, including globbing shortflags together, space or equals signs to attach values, optional values, and much more. See Invoking tasks. |
Task definition names are mirrored directly on the command-line, e.g
for task |
Removed |
Tasks names now get converted from underscores to hyphens. Eg. task
|
Ability to invoke multiple tasks in a single command line, e.g. |
Ported |
Works great! |
|
Ported |
Ported in 2.2. |
|
Removed |
To disable use of an agent permanently, set config value
|
|
Removed |
The config and kwarg versions of this are ported, but there is currently no CLI flag. Usual “you can set the config value at runtime with a shell env variable” clause is in effect, so this may not get ported, depending. |
|
Removed |
See the notes about interactive prompts going away in General / conceptual. Without mid-session prompts, there’s no need for this option. |
|
Ported |
|
|
Very little color work has been done yet and this is one of the potentially missing pieces. We’re unsure how often this was used in v1 so it’s possible it won’t show up again, but generally, we like using color as an additional output vector, so… |
|
|
Ported |
This is now the more standard |
|
Not ported yet, probably will be. |
|
|
Ported/Pending |
There’s no explicit connection cache anymore, so eager disconnection should be less necessary. However, investigation and potential feature toggles are still pending. |
|
Ported |
This is now split up into |
|
One can set the global Thus, if enough users notice the lack, we’ll consider a feature-add
that largely mimics the v1 behavior: string becomes first argument to
|
|
|
Removed |
These didn’t seem used enough to be worth porting over, especially
since they fall under the usual umbrella of “Paramiko-level connect
passthrough” covered by the |
|
Removed |
This is configurable via the config system and env vars. |
|
Ported |
Works basically the same as before - if given, is shorthand for executing any given tasks once per host. |
|
Ported |
Works same as v1, including ability to give multiple times to build a list of keys to try. |
|
Ported |
It’s now |
|
Ported |
This is now |
|
Removed |
Use environment variables to set the |
|
Not ported yet. |
|
|
Ported |
Now with bonus JSON list-format! Which incidentally replaces |
|
Removed |
This doesn’t really fit with the way modern command execution code views the world, so it’s gone. |
|
Not ported yet. |
|
|
Ported |
Is now |
|
Removed |
This is typically not very secure to begin with, and there are now many other avenues for setting the related configuration values, so they’re gone at least for now. |
|
See the notes around |
|
|
Removed |
Our gut says this is best left up to the configuration system’s env var
layer, or use of the |
|
Not ported yet. |
|
|
As noted under API organization, role lists are only partially applicable to the new API and we’re still feeling out whether/how they would work at a global or CLI level. |
|
|
Removed |
This is largely obviated by the new support for shell environment
variables (just do |
|
Removed |
Use the configuration system for this. |
|
Ported |
See |
|
Not ported yet. |
|
|
Removed |
This felt mostly like bloat to us and could require nontrivial parser changes to reimplement, so it’s out for now. |
|
Ported |
This is now |
|
Pending/Removed |
This isn’t super likely to come back as its own CLI flag but it may well return as a configuration value. |
|
Ported |
It’s now |
|
Ported |
Implemented in Invoke and preserved in |
|
Removed |
Most of the time, configuration (env vars for true runtime, or eg user/project level config files as appropriate) should be used for this, but it may return. |
|
Ported |
Ported as-is, no changes. |
|
Not ported yet, is pending an in depth rework of global (vs hand-instantiated) connection/group selection. |
|
|
Removed |
There’s no job queue anymore, or at least at present. Whatever replaces it (besides the already-implemented threading model) is likely to look pretty different. |
Shell command execution (local
/run
/sudo
)¶
General¶
Behaviors shared across either run
/sudo
, or all of
run
/sudo
/local
. Subsequent sections go into per-function
differences.
|
Removed |
All command execution is now unified; all three functions (now
methods on For example, in v1 |
Prompt auto-response, via |
Ported |
The In addition, |
|
Ported/Pending |
These are now methods on |
|
Ported |
The context managers were the only way to set environment variables at
any scope; in modern Fabric, subprocess shell environment is
controllable per-call (directly in |
Controlling subprocess output & other activity display text by
manipulating |
Ported/Pending |
The core concept of “output levels” is gone, likely to be replaced in the near term by a logging module (stdlib or other) which output levels poorly reimplemented. Command execution methods like |
|
Ported |
Primarily lives at the Invoke layer now, but applies to all command
execution, local or remote; see the |
|
Ported |
This has been thoroughly ported (and its behavior often improved)
including preservation of the Fabric 0.x and 1.x already changed this value around; during Fabric 1’s
long lifetime it became clear that neither default works for all or
even most users, so we opted to return the default to |
|
Removed |
This wasn’t terrifically useful, and often caused conceptual problems
in tandem with We recommend users who really need both streams to be merged, either
use shell redirection in their command, or set |
|
Ported |
This is now just |
|
Ported |
These are now |
|
Existing |
|
Return values are string-like objects with extra attributes like
|
Ported |
Return values are no longer string-a-likes with a semi-private API, but
are full fledged regular objects of type They do, however, still behave as booleans - just ones reflecting the exit code’s relation to zero instead of whether there was any stdout. |
|
Ported |
Not only is the new version of |
run
¶
|
Removed |
Non- See the matching line items for |
sudo
¶
Unless otherwise noted, all common run``+``sudo
args/functionality (e.g.
pty
, warn_only
etc) are covered above in the section on run
; the
below are sudo
specific.
|
Pending/Removed |
See the note above under We hope to upgrade |
|
Ported |
This is still here, and still called |
|
This has not been ported yet. |
local
¶
See the ‘general’ notes at top of this section for most details about the new
local
. A few specific extras are below.
|
Ported |
Basically the same as in v1, though there are now situations where
|
open_shell
¶
As noted in the main list, this is now shell
,
and behaves similarly to open_shell
(exit codes, if any, are ignored; a PTY
is assumed; etc). It has some improvements too, such as a return value (which
is slightly lacking compared to that from run
but still a big improvement over None
).
|
Removed |
If you needed this, you should instead try the modern version of
|
Utilities¶
Error handling via |
Ported |
The old functionality leaned too far in the “everything is a DSL” direction & didn’t offer enough value to offset how it gets in the way of experienced Pythonistas. These functions have been removed in favor of “just raise an exception”
(with one useful option being Invoke’s |
ANSI color helpers in |
Removed |
There seemed no point to poorly replicating one of the many fine terminal-massaging libraries out there (such as those listed in the description of #101) in the rewrite, so we didn’t. That said, it seems highly plausible we’ll end up vendoring such a library in the future to offer internal color support, at which point “baked-in” color helpers would again be within easy reach. |
|
Ported |
This is now |
|
Ported |
v1 required using a Fabric-specific ‘unwrap_tasks’ helper function somewhere in your Sphinx build pipeline; now you can instead just enable the new invocations.autodoc Sphinx mini-plugin in your extensions list; see link for details. |
|
Removed |
As with other host-string-related tools, these are gone and serve no
purpose. |
|
Pending |
Not ported yet; ideally we’ll just vendor a third party lib in Invoke. |
|
Removed |
No equivalent has been written for modern Fabric; now that the
connection/client objects are made explicit, one can simply
instantiate a new object with the same parameters (potentially with
sufficient timeout parameters to get past the reboot, if one doesn’t
want to manually call something like There is a small chance it will return if there appears to be enough
need; if so, it’s likely to be a more generic reconnection related
|
|
Removed |
This has not been ported, in part because the maintainers never used it themselves, and is unlikely to be directly reimplemented. However, its core use case of “require certain data to be available to run a given task” may return within the upcoming dependency framework. |
|
Removed |
Like |
Networking¶
|
Ported |
This is now the (You may specify a runtime, non-SSH-config-driven
|
|
Ported |
This continues to work as it did in v1. |
|
Ported |
This is now |
|
Removed |
In v1 this was simply a (partially implemented) stepping-back from the
original “just sys.exit on any error!” behavior. Modern Fabric is
significantly more exception-friendly; situations that would raise
|
|
Not ported yet. |
|
|
Not ported yet. |
|
|
Ported |
Connection timeout is now controllable both via the configuration
system (as |
Authentication¶
Note
Some env
keys from v1 were simply passthroughs to Paramiko’s
SSHClient.connect
method. Modern
Fabric gives you explicit control over the arguments it passes to that
method, via the connect_kwargs
configuration
subtree, and the below table will frequently refer you to that approach.
|
Ported |
Use |
|
Ported |
Use Also note that this used to perform double duty as connection and
sudo password; the latter is now found in the |
|
Ported |
Use |
|
Removed |
This has been dropped as unnecessary (& bug-prone) obfuscation of
Paramiko-level APIs; users should already know which type of key
they’re dealing with and instantiate a |
|
Ported |
Users who were setting this to |
|
Ported |
Use |
|
Ported/Pending |
Each However, we expect users may want a simpler way to set configuration
values that are turned into implicit |
Configuring |
Ported |
Still honored, along with a bunch of newly honored |
File transfer¶
The below feature breakdown applies to the put
and/or get
“operation”
functions from v1.
Transferring individual files owned by the local and remote user |
Ported |
Basic file transfer in either direction works and is offered as
The signature of these methods has been cleaned up compared to v1,
though their positional-argument essence ( |
Omit the ‘destination’ argument for implicit ‘relative to local
context’ behavior (e.g. |
Ported |
You should probably still be explicit, because this is Python. |
Use either file paths or file-like objects on either side of
the transfer operation (e.g. uploading a |
Ported |
This was a useful enough and simple enough trick to keep around. |
Preservation of source file mode at destination (e.g. ensuring an executable bit that would otherwise be dropped by the destination’s umask, is re-added.) |
Ported |
Not only was this ported, but it is now the default behavior. It may be disabled via kwarg if desired. |
Bundled |
Removed |
This was one of the absolute buggiest parts of v1 and never truly did
anything users could not do themselves with a followup call to
Should enough users pine for its loss, we may reconsider, but if we do it will be with a serious eye towards simplification and/or an approach not involving intermediate files. |
Recursive multi-file transfer (e.g. |
Removed |
This was another one of the buggiest parts of v1, and over time it
became clear that its maintenance burden far outweighed the fact that
it was poorly reinventing For one potential workaround, see the |
Remote file path tilde expansion |
Removed |
This behavior is ultimately unnecessary (one can simply leave the tilde off for the same result) and had a few pernicious bugs of its own, so it’s gone. |
Naming downloaded files after some aspect of the remote destination, to avoid overwriting during multi-server actions |
Ported |
Added back (to |
Configuration¶
In general, configuration has been massively improved over the old fabricrc
files; most config logic comes from Invoke’s configuration system, which offers a full-fledged configuration hierarchy (in-code
config, multiple config file locations, environment variables, CLI flags, and
more) and multiple file formats. Nearly all configuration avenues in Fabric 1
become, in modern Fabric, manipulation of whatever part of the config hierarchy
is most appropriate for your needs.
Modern versions of Fabric only make minor modifications to (or parameterizations of) Invoke’s setup; see our locally-specific config doc page for details.
Note
Make sure to look elsewhere in this document for details on any given v1
env
setting, as many have moved outside the configuration system into
object or method keyword arguments.
Modifying |
Ported |
To effect truly global-scale config changes, use config files, task-collection-level config data, or the invoking shell’s environment variables. |
Making locally scoped |
Ported/Pending |
Most of the use cases surrounding The remaining such use cases have been turned into context-manager
methods of |
SSH config file loading (off by default, limited to |
Ported |
Much improved: SSH config file loading is on by default (which can be changed), multiple sources are loaded and merged just like OpenSSH, and more besides; see Loading and using ssh_config files. In addition, we’ve added support for some |
contrib
¶
The old contrib
module represented “best practice” functions that did not,
themselves, require core support from the rest of Fabric but were built using
the same primitives available to users.
In modern Fabric, that responsibility has been removed from the core library into other standalone libraries which have their own identity & release process, typically either invocations (local-oriented code that does not use SSH) or patchwork (primarily remote-oriented code, though anything not explicitly dealing with both ends of the connection will work just as well locally.)
Those libraries are still a work in progress, not least because we still need to identify the best way to bridge the gap between them (as many operations are not intrinsically local-or-remote but can work on either end.)
Since they are by definition built on the core APIs available to all users, they currently get less development focus; users can always implement their own versions without sacrificing much (something less true for the core libraries.) We expect to put more work into curating these collections once the core APIs have settled down.
Details about what happened to each individual chunk of fabric.contrib
are
in the below table:
|
Ported |
Moved to |
|
Removed |
We aren’t even sure if this is useful a decade after it was written, given how much Django has surely changed since then. If you’re reading and are sad that this is gone, let us know! |
|
Ported/Pending |
Many of the more useful functions in this file have been ported to
Others, such as |
|
Ported |
Now |
|
Removed |
This did not seem worth porting; the overall pattern of “copy my local bits remotely” is already arguably an antipattern (vs repeatable deploys of artifacts, or at least remote checkout of a VCS tag) and if one is going down that road anyways, rsync is a much smarter choice. |
fabric.env
reference¶
Many/most of the members in v1’s fabric.env
are covered in the above
per-topic sections; any that are not covered elsewhere, live here. All are
explicitly noted as env.<name>
for ease of searching in your browser or
viewer.
A small handful of env vars were never publicly documented & were thus implicitly private; those are not represented here.
|
Removed |
Aborting as a concept is gone, just raise whatever exception seems most
reasonable to surface to an end user, or use |
|
Ported/Pending |
Fabric’s However, the details for that API (e.g. exposing the executor via a
task’s |
|
Ported/Pending |
See the notes for |
|
Ported |
This is now |
|
Ported |
This is now Note that remote-vs-local context for this data isn’t yet set up; see
the notes about |
|
Not ported yet, will probably get tackled as part of roles/host lists overhaul. |
|
|
Ported |
Is now a config option under the |
|
Removed |
We’re not entirely sure why v1 felt this was worth caching in the
config; if you need this info, just import and call
|
|
Differentiating parallel stdout/err is still a work in progress; we may end up reusing line-by-line logging and prefixing (ideally via actual logging) or we may try for something cleaner such as streaming to per-connection log files. |
|
|
Ported |
Prompt auto-response is now publicly implemented as the
|
|
Ported |
The loaded task |
|
Ported/Removed |
Invoke’s interrupt capture behavior is currently “always just send the
interrupt character to the subprocess and continue”, allowing
subprocesses to handle Allowing users to change this behavior via config is not yet implemented, and may not be, depending on whether anybody needs it - it was added as an option in v1 for backwards compat reasons. It is also technically possible to change interrupt behavior by
subclassing and overriding |
|
As noted in API organization, roles as a concept were ported to
We may delegate this to userland forever, but seems likely a
common-best-practice option (such as creating |
|
|
Not ported yet, but should involve some presumably minor updates to
|
|
|
Sudo command construction does not currently look at the config for anything but the actual sudo prompt. |
|
|
Ported |
Is now |
|
Removed |
As with most other functionality surrounding Fabric 1’s “jump straight
to |
|
Ported |
SSH config loading is now on by default, but an option remains to disable it. See Configuration for more. |
|
Removed |
Just |
Example upgrade process¶
This section goes over upgrading a small but nontrivial Fabric 1 fabfile to work with modern Fabric. It’s not meant to be exhaustive, merely illustrative; for a full list of how to upgrade individual features or concepts, see Upgrade specifics.
Sample original fabfile¶
Here’s a (slightly modified to concur with ‘modern’ Fabric 1 best practices) copy of Fabric 1’s final tutorial snippet, which we will use as our test case for upgrading:
from fabric.api import abort, env, local, run, settings, task
from fabric.contrib.console import confirm
env.hosts = ["my-server"]
@task
def test():
with settings(warn_only=True):
result = local("./manage.py test my_app", capture=True)
if result.failed and not confirm("Tests failed. Continue anyway?"):
abort("Aborting at user request.")
@task
def commit():
local("git add -p && git commit")
@task
def push():
local("git push")
@task
def prepare_deploy():
test()
commit()
push()
@task
def deploy():
code_dir = "/srv/django/myproject"
with settings(warn_only=True):
if run("test -d {}".format(code_dir)).failed:
cmd = "git clone user@vcshost:/path/to/repo/.git {}"
run(cmd.format(code_dir))
with cd(code_dir):
run("git pull")
run("touch app.wsgi")
We’ll port this directly, meaning the result will still be fabfile.py
,
though we’d like to note that writing your code in a more library-oriented
fashion - even just as functions not wrapped in @task
- can make testing
and reusing code easier.
Imports¶
In modern Fabric, we don’t need to import nearly as many functions, due to the emphasis on object methods instead of global functions. We only need the following:
@task
, as before, but coming from Invoke as it’s not SSH-specific;confirm
, which now comes from the Invocations library (also not SSH-specific; though Invocations is one of the descendants offabric.contrib
, which no longer exists);
from fabric import task
from invoke import Exit
from invocations.console import confirm
Host list¶
The idea of a predefined global host list is gone; there is currently no
direct replacement. In general, users can set up their own execution context,
creating explicit fabric.connection.Connection
and/or fabric.group.Group
objects as needed; core Fabric is in the process of building convenience
helpers on top of this, but “create your own Connections” will always be there
as a backstop.
Speaking of convenience helpers: most of the functionality of fab --hosts
and @hosts
has been ported over – the former directly (see
--hosts
), the latter as a @task
keyword
argument. Thus, for now our example will be turning the global env.hosts
into a lightweight module-level variable declaration, intended for use in the
subsequent calls to @task
:
my_hosts = ["my-server"]
Note
This is an area under active development, so feedback is welcomed.
Test task¶
The first task in the fabfile uses a good spread of the API. We’ll outline the changes here (though again, all details are in Upgrade specifics):
Declaring a function as a task is nearly the same as before: use a
@task
decorator (which, in modern Fabric, can take more optional keyword arguments than its predecessor, including some which replace some of v1’s decorators).@task
-wrapped functions must now take an explicit initial context argument, whose value will be afabric.connection.Connection
object at runtime.The use of
with settings(warn_only=True)
can be replaced by a simple kwarg to thelocal
call.That
local
call is now a method call on thefabric.connection.Connection
,fabric.connection.Connection.local
.capture
is no longer a useful argument; we can now capture and display at the same time, locally or remotely. If you don’t actually want a local subprocess to mirror its stdout/err while it runs, you can simply sayhide=True
(orhide="stdout"
or etc.)Result objects are pretty similar between versions; modern Fabric’s results no longer pretend to “be” strings, but instead act more like booleans, acting truthy if the command exited cleanly, and falsey otherwise. In terms of attributes exhibited, most of the same info is available, and more besides.
abort
is gone; you should use whatever exceptions you feel are appropriate, orExit
for asys.exit
equivalent. (Or just callsys.exit
if you want a no-questions-asked immediate exit that even our CLI machinery won’t touch.)
The result:
@task
def test(c):
result = c.local("./manage.py test my_app", warn=True)
if not result and not confirm("Tests failed. Continue anyway?"):
raise Exit("Aborting at user request.")
Other simple tasks¶
The next two tasks are simple one-liners, and you’ve already seen what replaced
the global local
function:
@task
def commit(c):
c.local("git add -p && git commit")
@task
def push(c):
c.local("git push")
Calling tasks from other tasks¶
This is another area that is in flux at the Invoke level, but for now, we can simply call the other tasks as functions, just as was done in v1. The main difference is that we want to pass along our context object to preserve the configuration context (such as loaded config files or CLI flags):
@task
def prepare_deploy(c):
test(c)
commit(c)
push(c)
Actual remote steps¶
Note that up to this point, nothing truly Fabric-related has been in play -
fabric.connection.Connection.local
is just a rebinding of Context.run
, Invoke’s local subprocess execution method. Now
we get to the actual deploy step, which invokes
fabric.connection.Connection.run
instead, executing remotely (on whichever
host the fabric.connection.Connection
has been bound to).
with cd
is not fully implemented for the remote side of things, but we
expect it will be soon. For now we fall back to command chaining with &&
.
And, notably, now that we care about selecting host targets, we refer to our
earlier definition of a default host list – my_hosts
– when declaring the
default host list for this task.
@task(hosts=my_hosts)
def deploy(c):
code_dir = "/srv/django/myproject"
if not c.run("test -d {}".format(code_dir), warn=True):
cmd = "git clone user@vcshost:/path/to/repo/.git {}"
c.run(cmd.format(code_dir))
c.run("cd {} && git pull".format(code_dir))
c.run("cd {} && touch app.wsgi".format(code_dir))
The whole thing¶
Now we have the entire, upgraded fabfile that will work with modern Fabric:
from invoke import Exit
from invocations.console import confirm
from fabric import task
my_hosts = ["my-server"]
@task
def test(c):
result = c.local("./manage.py test my_app", warn=True)
if not result and not confirm("Tests failed. Continue anyway?"):
raise Exit("Aborting at user request.")
@task
def commit(c):
c.local("git add -p && git commit")
@task
def push(c):
c.local("git push")
@task
def prepare_deploy(c):
test(c)
commit(c)
push(c)
@task(hosts=my_hosts)
def deploy(c):
code_dir = "/srv/django/myproject"
if not c.run("test -d {}".format(code_dir), warn=True):
cmd = "git clone user@vcshost:/path/to/repo/.git {}"
c.run(cmd.format(code_dir))
c.run("cd {} && git pull".format(code_dir))
c.run("cd {} && touch app.wsgi".format(code_dir))