├── .gitignore ├── Makefile ├── README.md ├── api ├── contrib │ ├── console.rst │ ├── django.rst │ ├── files.rst │ └── project.rst └── core │ ├── colors.rst │ ├── context_managers.rst │ ├── decorators.rst │ ├── docs.rst │ ├── network.rst │ ├── operations.rst │ ├── tasks.rst │ └── utils.rst ├── conf.py ├── index.rst ├── make.bat ├── tutorial.rst └── usage ├── env.rst ├── execution.rst ├── fab.rst ├── fabfiles.rst ├── interactivity.rst ├── library.rst ├── output_controls.rst ├── parallel.rst ├── ssh.rst └── tasks.rst /.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Fabric-docs-cn.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Fabric-docs-cn.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/Fabric-docs-cn" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Fabric-docs-cn" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Fabric 官方文档的民间翻译中文版 2 | ============== 3 | 4 | 基于 2014-6-5 的官方代码库翻译,对应程序 v1.8 版本。 5 | 6 | 项目官方网站 fabfile.org 7 | -------------------------------------------------------------------------------- /api/contrib/console.rst: -------------------------------------------------------------------------------- 1 | Console Output Utilities 2 | ======================== 3 | 4 | .. automodule:: fabric.contrib.console 5 | :members: 6 | -------------------------------------------------------------------------------- /api/contrib/django.rst: -------------------------------------------------------------------------------- 1 | ================== 2 | Django Integration 3 | ================== 4 | 5 | .. automodule:: fabric.contrib.django 6 | :members: 7 | -------------------------------------------------------------------------------- /api/contrib/files.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | File and Directory Management 3 | ============================= 4 | 5 | .. automodule:: fabric.contrib.files 6 | :members: 7 | -------------------------------------------------------------------------------- /api/contrib/project.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | Project Tools 3 | ============= 4 | 5 | .. automodule:: fabric.contrib.project 6 | :members: 7 | -------------------------------------------------------------------------------- /api/core/colors.rst: -------------------------------------------------------------------------------- 1 | ====================== 2 | Color output functions 3 | ====================== 4 | 5 | .. automodule:: fabric.colors 6 | :members: 7 | :undoc-members: 8 | -------------------------------------------------------------------------------- /api/core/context_managers.rst: -------------------------------------------------------------------------------- 1 | ================ 2 | Context Managers 3 | ================ 4 | 5 | .. automodule:: fabric.context_managers 6 | :members: 7 | -------------------------------------------------------------------------------- /api/core/decorators.rst: -------------------------------------------------------------------------------- 1 | ========== 2 | Decorators 3 | ========== 4 | 5 | .. automodule:: fabric.decorators 6 | :members: hosts, roles, runs_once, serial, parallel, task, with_settings 7 | -------------------------------------------------------------------------------- /api/core/docs.rst: -------------------------------------------------------------------------------- 1 | ===================== 2 | Documentation helpers 3 | ===================== 4 | 5 | .. automodule:: fabric.docs 6 | :members: 7 | -------------------------------------------------------------------------------- /api/core/network.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | Network 3 | ======= 4 | 5 | .. automodule:: fabric.network 6 | 7 | .. autofunction:: disconnect_all 8 | -------------------------------------------------------------------------------- /api/core/operations.rst: -------------------------------------------------------------------------------- 1 | ========== 2 | Operations 3 | ========== 4 | 5 | .. automodule:: fabric.operations 6 | :members: 7 | -------------------------------------------------------------------------------- /api/core/tasks.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | Tasks 3 | ===== 4 | 5 | .. automodule:: fabric.tasks 6 | :members: Task, WrappedCallableTask, execute 7 | -------------------------------------------------------------------------------- /api/core/utils.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | Utils 3 | ===== 4 | 5 | .. automodule:: fabric.utils 6 | :members: 7 | -------------------------------------------------------------------------------- /conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Fabric-docs-cn documentation build configuration file, created by 4 | # sphinx-quickstart on Thu Jun 05 22:39:25 2014. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | import sys 16 | import os 17 | 18 | # If extensions (or modules to document with autodoc) are in another directory, 19 | # add these directories to sys.path here. If the directory is relative to the 20 | # documentation root, use os.path.abspath to make it absolute, like shown here. 21 | #sys.path.insert(0, os.path.abspath('.')) 22 | 23 | # -- General configuration ------------------------------------------------ 24 | 25 | # If your documentation needs a minimal Sphinx version, state it here. 26 | #needs_sphinx = '1.0' 27 | 28 | # Add any Sphinx extension module names here, as strings. They can be 29 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 30 | # ones. 31 | extensions = [] 32 | 33 | # Add any paths that contain templates here, relative to this directory. 34 | templates_path = ['_templates'] 35 | 36 | # The suffix of source filenames. 37 | source_suffix = '.rst' 38 | 39 | # The encoding of source files. 40 | #source_encoding = 'utf-8-sig' 41 | 42 | # The master toctree document. 43 | master_doc = 'index' 44 | 45 | # General information about the project. 46 | project = u'Fabric-docs-cn' 47 | copyright = u'2014, Felix.Lu' 48 | 49 | # The version info for the project you're documenting, acts as replacement for 50 | # |version| and |release|, also used in various other places throughout the 51 | # built documents. 52 | # 53 | # The short X.Y version. 54 | version = '1.8' 55 | # The full version, including alpha/beta/rc tags. 56 | release = '1.8' 57 | 58 | # The language for content autogenerated by Sphinx. Refer to documentation 59 | # for a list of supported languages. 60 | #language = None 61 | 62 | # There are two options for replacing |today|: either, you set today to some 63 | # non-false value, then it is used: 64 | #today = '' 65 | # Else, today_fmt is used as the format for a strftime call. 66 | #today_fmt = '%B %d, %Y' 67 | 68 | # List of patterns, relative to source directory, that match files and 69 | # directories to ignore when looking for source files. 70 | exclude_patterns = ['_build'] 71 | 72 | # The reST default role (used for this markup: `text`) to use for all 73 | # documents. 74 | #default_role = None 75 | 76 | # If true, '()' will be appended to :func: etc. cross-reference text. 77 | #add_function_parentheses = True 78 | 79 | # If true, the current module name will be prepended to all description 80 | # unit titles (such as .. function::). 81 | #add_module_names = True 82 | 83 | # If true, sectionauthor and moduleauthor directives will be shown in the 84 | # output. They are ignored by default. 85 | #show_authors = False 86 | 87 | # The name of the Pygments (syntax highlighting) style to use. 88 | pygments_style = 'sphinx' 89 | 90 | # A list of ignored prefixes for module index sorting. 91 | #modindex_common_prefix = [] 92 | 93 | # If true, keep warnings as "system message" paragraphs in the built documents. 94 | #keep_warnings = False 95 | 96 | 97 | # -- Options for HTML output ---------------------------------------------- 98 | 99 | # The theme to use for HTML and HTML Help pages. See the documentation for 100 | # a list of builtin themes. 101 | html_theme = 'default' 102 | 103 | # Theme options are theme-specific and customize the look and feel of a theme 104 | # further. For a list of options available for each theme, see the 105 | # documentation. 106 | #html_theme_options = {} 107 | 108 | # Add any paths that contain custom themes here, relative to this directory. 109 | #html_theme_path = [] 110 | 111 | # The name for this set of Sphinx documents. If None, it defaults to 112 | # " v documentation". 113 | #html_title = None 114 | 115 | # A shorter title for the navigation bar. Default is the same as html_title. 116 | #html_short_title = None 117 | 118 | # The name of an image file (relative to this directory) to place at the top 119 | # of the sidebar. 120 | #html_logo = None 121 | 122 | # The name of an image file (within the static path) to use as favicon of the 123 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 124 | # pixels large. 125 | #html_favicon = None 126 | 127 | # Add any paths that contain custom static files (such as style sheets) here, 128 | # relative to this directory. They are copied after the builtin static files, 129 | # so a file named "default.css" will overwrite the builtin "default.css". 130 | html_static_path = ['_static'] 131 | 132 | # Add any extra paths that contain custom files (such as robots.txt or 133 | # .htaccess) here, relative to this directory. These files are copied 134 | # directly to the root of the documentation. 135 | #html_extra_path = [] 136 | 137 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 138 | # using the given strftime format. 139 | #html_last_updated_fmt = '%b %d, %Y' 140 | 141 | # If true, SmartyPants will be used to convert quotes and dashes to 142 | # typographically correct entities. 143 | #html_use_smartypants = True 144 | 145 | # Custom sidebar templates, maps document names to template names. 146 | #html_sidebars = {} 147 | 148 | # Additional templates that should be rendered to pages, maps page names to 149 | # template names. 150 | #html_additional_pages = {} 151 | 152 | # If false, no module index is generated. 153 | #html_domain_indices = True 154 | 155 | # If false, no index is generated. 156 | #html_use_index = True 157 | 158 | # If true, the index is split into individual pages for each letter. 159 | #html_split_index = False 160 | 161 | # If true, links to the reST sources are added to the pages. 162 | #html_show_sourcelink = True 163 | 164 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 165 | #html_show_sphinx = True 166 | 167 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 168 | #html_show_copyright = True 169 | 170 | # If true, an OpenSearch description file will be output, and all pages will 171 | # contain a tag referring to it. The value of this option must be the 172 | # base URL from which the finished HTML is served. 173 | #html_use_opensearch = '' 174 | 175 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 176 | #html_file_suffix = None 177 | 178 | # Output file base name for HTML help builder. 179 | htmlhelp_basename = 'Fabric-docs-cndoc' 180 | 181 | 182 | # -- Options for LaTeX output --------------------------------------------- 183 | 184 | latex_elements = { 185 | # The paper size ('letterpaper' or 'a4paper'). 186 | #'papersize': 'letterpaper', 187 | 188 | # The font size ('10pt', '11pt' or '12pt'). 189 | #'pointsize': '10pt', 190 | 191 | # Additional stuff for the LaTeX preamble. 192 | #'preamble': '', 193 | } 194 | 195 | # Grouping the document tree into LaTeX files. List of tuples 196 | # (source start file, target name, title, 197 | # author, documentclass [howto, manual, or own class]). 198 | latex_documents = [ 199 | ('index', 'Fabric-docs-cn.tex', u'Fabric-docs-cn Documentation', 200 | u'Felix.Lu', 'manual'), 201 | ] 202 | 203 | # The name of an image file (relative to this directory) to place at the top of 204 | # the title page. 205 | #latex_logo = None 206 | 207 | # For "manual" documents, if this is true, then toplevel headings are parts, 208 | # not chapters. 209 | #latex_use_parts = False 210 | 211 | # If true, show page references after internal links. 212 | #latex_show_pagerefs = False 213 | 214 | # If true, show URL addresses after external links. 215 | #latex_show_urls = False 216 | 217 | # Documents to append as an appendix to all manuals. 218 | #latex_appendices = [] 219 | 220 | # If false, no module index is generated. 221 | #latex_domain_indices = True 222 | 223 | 224 | # -- Options for manual page output --------------------------------------- 225 | 226 | # One entry per manual page. List of tuples 227 | # (source start file, name, description, authors, manual section). 228 | man_pages = [ 229 | ('index', 'fabric-docs-cn', u'Fabric-docs-cn Documentation', 230 | [u'Felix.Lu'], 1) 231 | ] 232 | 233 | # If true, show URL addresses after external links. 234 | #man_show_urls = False 235 | 236 | 237 | # -- Options for Texinfo output ------------------------------------------- 238 | 239 | # Grouping the document tree into Texinfo files. List of tuples 240 | # (source start file, target name, title, author, 241 | # dir menu entry, description, category) 242 | texinfo_documents = [ 243 | ('index', 'Fabric-docs-cn', u'Fabric-docs-cn Documentation', 244 | u'Felix.Lu', 'Fabric-docs-cn', 'One line description of project.', 245 | 'Miscellaneous'), 246 | ] 247 | 248 | # Documents to append as an appendix to all manuals. 249 | #texinfo_appendices = [] 250 | 251 | # If false, no module index is generated. 252 | #texinfo_domain_indices = True 253 | 254 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 255 | #texinfo_show_urls = 'footnote' 256 | 257 | # If true, do not generate a @detailmenu in the "Top" node's menu. 258 | #texinfo_no_detailmenu = False 259 | -------------------------------------------------------------------------------- /index.rst: -------------------------------------------------------------------------------- 1 | ================================== 2 | 欢迎访问 Fabric 中文版文档! 3 | ================================== 4 | 5 | 本站覆盖了 Fabric 的用法和 API 文档。若想了解 Fabric 是什么,包括它的更新日志和如何维护该项目,请访问 `Fabric 项目官方网站 `_ 。 6 | 7 | 入门指导 8 | -------- 9 | 10 | 对于新用户,与/或想大概了解 Fabric 的基本功能的同学,请看 :doc:`tutorial` 。本文档的其他部分将假设你至少已经大概熟悉其中的内容。 11 | 12 | .. toctree:: 13 | :hidden: 14 | 15 | tutorial 16 | 17 | 18 | .. _usage-docs: 19 | 20 | 用法文档 21 | ------------------- 22 | 23 | 下面的列表包含了 Fabric 散文(非 API)文档的所有主要章节。这些内容在 :doc:`tutorial` 中提到的概念基础上进行了扩展,并覆盖了一些进阶主题。 24 | 25 | .. toctree:: 26 | :maxdepth: 2 27 | :glob: 28 | 29 | usage/* 30 | 31 | 32 | .. _api_docs: 33 | 34 | API 文档 35 | ----------------- 36 | 37 | Fabric 维护了两套 API 文档,它们都是根据代码中的 docstring 自动生成的,也十分详尽。 38 | 39 | .. _core-api: 40 | 41 | 核心 API 42 | ~~~~~~~~ 43 | 44 | **核心** API 是指构成 Fabric 基础构建块的函数、类和方法(例如 `~fabric.operations.run` 和 `~fabric.operations.sudo`)。而其他部分(下文的“扩展 API”和用户的 fabfile)都是在这些核心 API 的基础之上构建的。 45 | 46 | .. toctree:: 47 | :maxdepth: 和 48 | :glob: 49 | 50 | api/core/* 51 | 52 | .. _contrib-api: 53 | 54 | 扩展 API 55 | ~~~~~~~~~~~ 56 | 57 | Fabric 的 **扩展** 包包括常用而有用的工具(通常是从用户的 fabfile 中合并进来的),可用于用户 I/O、修改远程文件等任务中。核心 API 倾向于保持小巧、不随意变更,扩展包则会随着更多的用户案例被解决并添加进来,而不断成长进化(同时尽量保持向后兼容)。 58 | 59 | .. toctree:: 60 | :maxdepth: 1 61 | :glob: 62 | 63 | api/contrib/* 64 | -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | goto end 41 | ) 42 | 43 | if "%1" == "clean" ( 44 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 45 | del /q /s %BUILDDIR%\* 46 | goto end 47 | ) 48 | 49 | 50 | %SPHINXBUILD% 2> nul 51 | if errorlevel 9009 ( 52 | echo. 53 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 54 | echo.installed, then set the SPHINXBUILD environment variable to point 55 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 56 | echo.may add the Sphinx directory to PATH. 57 | echo. 58 | echo.If you don't have Sphinx installed, grab it from 59 | echo.http://sphinx-doc.org/ 60 | exit /b 1 61 | ) 62 | 63 | if "%1" == "html" ( 64 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 68 | goto end 69 | ) 70 | 71 | if "%1" == "dirhtml" ( 72 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 76 | goto end 77 | ) 78 | 79 | if "%1" == "singlehtml" ( 80 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 84 | goto end 85 | ) 86 | 87 | if "%1" == "pickle" ( 88 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can process the pickle files. 92 | goto end 93 | ) 94 | 95 | if "%1" == "json" ( 96 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 97 | if errorlevel 1 exit /b 1 98 | echo. 99 | echo.Build finished; now you can process the JSON files. 100 | goto end 101 | ) 102 | 103 | if "%1" == "htmlhelp" ( 104 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 105 | if errorlevel 1 exit /b 1 106 | echo. 107 | echo.Build finished; now you can run HTML Help Workshop with the ^ 108 | .hhp project file in %BUILDDIR%/htmlhelp. 109 | goto end 110 | ) 111 | 112 | if "%1" == "qthelp" ( 113 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 117 | .qhcp project file in %BUILDDIR%/qthelp, like this: 118 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Fabric-docs-cn.qhcp 119 | echo.To view the help file: 120 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Fabric-docs-cn.ghc 121 | goto end 122 | ) 123 | 124 | if "%1" == "devhelp" ( 125 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished. 129 | goto end 130 | ) 131 | 132 | if "%1" == "epub" ( 133 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 137 | goto end 138 | ) 139 | 140 | if "%1" == "latex" ( 141 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 145 | goto end 146 | ) 147 | 148 | if "%1" == "latexpdf" ( 149 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 150 | cd %BUILDDIR%/latex 151 | make all-pdf 152 | cd %BUILDDIR%/.. 153 | echo. 154 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 155 | goto end 156 | ) 157 | 158 | if "%1" == "latexpdfja" ( 159 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 160 | cd %BUILDDIR%/latex 161 | make all-pdf-ja 162 | cd %BUILDDIR%/.. 163 | echo. 164 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 165 | goto end 166 | ) 167 | 168 | if "%1" == "text" ( 169 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 170 | if errorlevel 1 exit /b 1 171 | echo. 172 | echo.Build finished. The text files are in %BUILDDIR%/text. 173 | goto end 174 | ) 175 | 176 | if "%1" == "man" ( 177 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 178 | if errorlevel 1 exit /b 1 179 | echo. 180 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 181 | goto end 182 | ) 183 | 184 | if "%1" == "texinfo" ( 185 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 186 | if errorlevel 1 exit /b 1 187 | echo. 188 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 189 | goto end 190 | ) 191 | 192 | if "%1" == "gettext" ( 193 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 194 | if errorlevel 1 exit /b 1 195 | echo. 196 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 197 | goto end 198 | ) 199 | 200 | if "%1" == "changes" ( 201 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 202 | if errorlevel 1 exit /b 1 203 | echo. 204 | echo.The overview file is in %BUILDDIR%/changes. 205 | goto end 206 | ) 207 | 208 | if "%1" == "linkcheck" ( 209 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 210 | if errorlevel 1 exit /b 1 211 | echo. 212 | echo.Link check complete; look for any errors in the above output ^ 213 | or in %BUILDDIR%/linkcheck/output.txt. 214 | goto end 215 | ) 216 | 217 | if "%1" == "doctest" ( 218 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 219 | if errorlevel 1 exit /b 1 220 | echo. 221 | echo.Testing of doctests in the sources finished, look at the ^ 222 | results in %BUILDDIR%/doctest/output.txt. 223 | goto end 224 | ) 225 | 226 | if "%1" == "xml" ( 227 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 228 | if errorlevel 1 exit /b 1 229 | echo. 230 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 231 | goto end 232 | ) 233 | 234 | if "%1" == "pseudoxml" ( 235 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 236 | if errorlevel 1 exit /b 1 237 | echo. 238 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 239 | goto end 240 | ) 241 | 242 | :end 243 | -------------------------------------------------------------------------------- /tutorial.rst: -------------------------------------------------------------------------------- 1 | ===================== 2 | 入门导览 3 | ===================== 4 | 5 | 欢迎来到 Fabric! 6 | 7 | 本文档走马观花式地介绍 Fabric 特性,也是对其使用的快速指导。其他文档(这里通篇的链接都指向它们)可以在 :ref:`用法文档 ` 里找到——请不要忘记也看看它们。 8 | 9 | Fabric 是什么? 10 | =============== 11 | 12 | 正如 ``README`` 所说: 13 | 14 | Fabric 是一个 Python (2.5-2.7) 库和命令行工具,用来流水线化执行 SSH 以部署应用或系统管理任务。 15 | 16 | 更具体地说,Fabric 是: 17 | 18 | * 一个让你通过 **命令行** 执行 **任意 Python 函数** 的工具; 19 | * 一个让通过 SSH 执行 Shell 命令更加 **容易** 和 **蟒样** 的子程序库(建立于一个更低层次的库)。 20 | 21 | 自然地,大部分用户把这两件事结合着用,使用 Fabric 来写和执行 Python 函数或 **任务** ,以实现与远程服务器的自动化交互。让我们先睹为快吧。 22 | 23 | 你好, ``fab`` 24 | ============== 25 | 26 | 如果没有下面这个国际惯例,这个文档恐怕不能算是个合格的入门指导:: 27 | 28 | def hello(): 29 | print("Hello world!") 30 | 31 | 把上述代码放在你当前的工作目录中一个名为 ``fabfile.py`` 的 Python 模块文件中。然后这个 ``hello`` 函数就可以用安装 Fabric 时顺便装上的 ``fab`` 工具来执行了,它将如你所料地工作:: 32 | 33 | $ fab hello 34 | Hello world! 35 | 36 | Done. 37 | 38 | 这就是这个模块的所有作用。这个功能让 Fabric 可以作为一个极其基本的构建工具来使用,简单到甚至不用导入它的任何 API。 39 | 40 | .. note:: 41 | 42 | 这个 ``fab`` 简单地导入了你的 fabfile 并执行你定义的一个或多个函数。这里并没有任何魔术——任何你能在一个普通 Python 模块中做的事情都同样可以在一个 fabfile 中完成。 43 | 44 | .. seealso:: :ref:`execution-strategy`, :doc:`/usage/tasks`, :doc:`/usage/fab` 45 | 46 | 47 | 任务参数 48 | ============== 49 | 50 | 就像你在常规的 Python 编程中那样,在执行任务时传递一些运行时参数经常能帮上大忙。Fabric 支持用兼容 Shell 的参数用法: ``<任务名>:<参数>, <关键字参数名>=<参数值>,...`` 虽然有点勉强,但可以扩展上面的例子,让它只向你 say hello:: 51 | 52 | def hello(name="world"): 53 | print("Hello %s!" % name) 54 | 55 | 默认情况下,调用 ``fab hello`` 仍然会像之前那样工作,但现在我们可以做些个性化定制了:: 56 | 57 | $ fab hello:name=Jeff 58 | Hello Jeff! 59 | 60 | Done. 61 | 62 | 用过 Python 编程的同学可能已经猜到了,这样调用也是完全一样的:: 63 | 64 | $ fab hello:Jeff 65 | Hello Jeff! 66 | 67 | Done. 68 | 69 | 目前,参数值只能作为 Python 字符串来使用,如果要使用复杂类型,例如列表,会需要一些字符串操作处理。将来的版本可能会添加一个类型转换系统,以简化这类处理。 70 | 71 | .. seealso:: :ref:`task-arguments` 72 | 73 | 本地命令 74 | ============== 75 | 76 | 在前面的例子中, ``fab`` 实际上只节省了数行 ``if __name__ == "__main__"`` 这样的固定样板代码而已。Fabric 更多地被设计为使用它自己的 API,它们包括执行 Shell 命令、传送文件等等的函数(或 **操作** )。 77 | 78 | 我们以一个 Web 应用为例来创建一个 fabfile。具体的情景如下:这个 Web 应用用一台远程服务器 ``vcshost`` 上的 Git 管理代码,我们把它的代码库克隆到了本地 ``localhost`` 中。当我们把修改后的代码 push 回 ``vcshost`` 的时候,我们想自动就立即把新的版本安装到另一台远程服务器 ``my_server`` 上。我们将用自动化的本地和远程 Git 命令来完成这些工作。 79 | 80 | fabfile 文件最好放在一个项目的根目录:: 81 | 82 | . 83 | |-- __init__.py 84 | |-- app.wsgi 85 | |-- fabfile.py <-- our fabfile! 86 | |-- manage.py 87 | `-- my_app 88 | |-- __init__.py 89 | |-- models.py 90 | |-- templates 91 | | `-- index.html 92 | |-- tests.py 93 | |-- urls.py 94 | `-- views.py 95 | 96 | .. note:: 97 | 98 | 我们在这里用的是一个 Django 应用,但这仅仅是个例子——Fabric 并未与任何外部代码绑定,除了它的 SSH 库。 99 | 100 | 作为起步,可能我们希望先执行测试,然后再提交到 VCS(版本控制系统),为部署作好准备:: 101 | 102 | from fabric.api import local 103 | 104 | def prepare_deploy(): 105 | local("./manage.py test my_app") 106 | local("git add -p && git commit") 107 | local("git push") 108 | 109 | 这段代码的输出会是这样:: 110 | 111 | $ fab prepare_deploy 112 | [localhost] run: ./manage.py test my_app 113 | Creating test database... 114 | Creating tables 115 | Creating indexes 116 | .......................................... 117 | ---------------------------------------------------------------------- 118 | Ran 42 tests in 9.138s 119 | 120 | OK 121 | Destroying test database... 122 | 123 | [localhost] run: git add -p && git commit 124 | 125 | 126 | 127 | [localhost] run: git push 128 | 129 | 130 | 131 | Done. 132 | 133 | 这段代码很简单,导入一个 Fabric API: `~fabric.operations.local` ,然后用它执行本地 Shell 命令并与之交互,剩下的 Fabric API 也是类似的——它们都只是 Python 而已。 134 | 135 | .. seealso:: :doc:`api/core/operations`, :ref:`fabfile-discovery` 136 | 137 | 用你的方式来组织 138 | ==================== 139 | 140 | 因为 Fabric“只是 Python”,你可以以你想要的任何方式来组织你的 fabfile。例如,把任务分割成多个子任务:: 141 | 142 | from fabric.api import local 143 | 144 | def test(): 145 | local("./manage.py test my_app") 146 | 147 | def commit(): 148 | local("git add -p && git commit") 149 | 150 | def push(): 151 | local("git push") 152 | 153 | def prepare_deploy(): 154 | test() 155 | commit() 156 | push() 157 | 158 | 这个 ``prepare_deploy`` 任务仍可以像之前那样调用,但现在只要你想,就可以调用更细粒度的子任务了。 159 | 160 | 故障 161 | ======= 162 | 163 | 我们的基本案例已经可以正常工作了,但如果测试失败了会发生什么事?没准我们想来个急刹车,并在部署之前修复这些失败的测试。 164 | 165 | Fabric 会检查被调用程序的返回值,如果这些程序没有干净地退出,Fabric 会放弃操作。下面我们就来看看如果一个测试用例遇到错误时会发生什么事:: 166 | 167 | $ fab prepare_deploy 168 | [localhost] run: ./manage.py test my_app 169 | Creating test database... 170 | Creating tables 171 | Creating indexes 172 | .............E............................ 173 | ====================================================================== 174 | ERROR: testSomething (my_project.my_app.tests.MainTests) 175 | ---------------------------------------------------------------------- 176 | Traceback (most recent call last): 177 | [...] 178 | 179 | ---------------------------------------------------------------------- 180 | Ran 42 tests in 9.138s 181 | 182 | FAILED (errors=1) 183 | Destroying test database... 184 | 185 | Fatal error: local() encountered an error (return code 2) while executing './manage.py test my_app' 186 | 187 | Aborting. 188 | 189 | 太好了!我们什么都不用做,Fabric 检测到了错误并放弃了操作,不会继续执行 ``commit`` 任务。 190 | 191 | .. seealso:: :ref:`故障处理(用法文档) ` 192 | 193 | 故障处理 194 | ---------------- 195 | 196 | 但如果我们想更加灵活,给用户另一个选择,又该怎么办呢?一个名为 :ref:`warn_only` 的设置(或 **环境变量** ,经常缩写为 **env var** )可以把放弃变成警告,使得灵活处理错误成为现实。 197 | 198 | 让我们把这个设置丢到我们的 ``test`` 函数中,然后看看这个 `~fabric.operations.local` 调用的结果如何:: 199 | 200 | from __future__ import with_statement 201 | from fabric.api import local, settings, abort 202 | from fabric.contrib.console import confirm 203 | 204 | def test(): 205 | with settings(warn_only=True): 206 | result = local('./manage.py test my_app', capture=True) 207 | if result.failed and not confirm("Tests failed. Continue anyway?"): 208 | abort("Aborting at user request.") 209 | 210 | [...] 211 | 212 | 在添加这个新特性时,我们引入了一些新东西: 213 | 214 | * 在 Python 2.5 中,需要导入 ``__future__`` 才能使用 ``with`` ; 215 | * Fabric 的 `contrib.console ` 子模块包含了 `~fabric.contrib.console.confirm` 函数,用来做简单的 yes/no 提示; 216 | * 上下文管理器 `~fabric.context_managers.settings` 用来将设置应用到某个特定的代码块中; 217 | * 运行命令的操作,如 `~fabric.operations.local` ,可以返回一个包含该操作的结果信息(例如 ``.failed`` 或 ``.return_code`` )的对象; 218 | * 还有 `~fabric.utils.abort` 函数,可以用来手工取消执行。 219 | 220 | 然而,即使在增加了上述复杂度之后,整个处理过程仍然很容易理解,而且它已经远比之前灵活了。 221 | 222 | .. seealso:: :doc:`api/core/context_managers`, :ref:`env-vars` 223 | 224 | 建立连接 225 | ================== 226 | 227 | 我们开始让 fabfile 回到主旨吧:定义一个 ``deploy`` 任务,让它在一台或多台远程服务器上运行,并保证代码是最新的:: 228 | 229 | def deploy(): 230 | code_dir = '/srv/django/myproject' 231 | with cd(code_dir): 232 | run("git pull") 233 | run("touch app.wsgi") 234 | 235 | 这里再次引入了一些新的概念: 236 | 237 | * Fabric 就是 Python——所以我们可以自由地使用变量、字符串等常规的 Python 代码结构; 238 | * `~fabric.context_managers.cd` 是一个很方便的前缀命令,相当于执行 ``cd /to/some/directory`` 命令,这个命令和 `~fabric.context_managers.lcd` 一样,不过后者针对本地; 239 | * `~fabric.operations.run` 则和 `~fabric.operations.local` 类似,但它是运行 **远程** 命令而非本地。 240 | 241 | 我们还需要确认在文件顶部导入了新的函数:: 242 | 243 | from __future__ import with_statement 244 | from fabric.api import local, settings, abort, run, cd 245 | from fabric.contrib.console import confirm 246 | 247 | 改好之后,我们再来部署:: 248 | 249 | $ fab deploy 250 | No hosts found. Please specify (single) host string for connection: my_server 251 | [my_server] run: git pull 252 | [my_server] out: Already up-to-date. 253 | [my_server] out: 254 | [my_server] run: touch app.wsgi 255 | 256 | Done. 257 | 258 | 我们从来没有在 fabfile 中指定任何连接信息,所以 Fabric 不知道该在哪里运行那些远程命令。当遇到这种情况,Fabric 会在运行时提示我们。连接的定义使用 SSH 风格的“主机串”(例如: ``user@host:port`` ),默认使用你的本地用户名——所以在这个例子中,我们只需要指定主机名 ``my_server`` 。 259 | 260 | 远程交互 261 | -------------------- 262 | 263 | 如果你已经签出过代码, ``git pull`` 就能很好地工作——但如果这是第一次部署呢?如果还能用 ``git clone`` 来处理这种情况那才叫棒呢:: 264 | 265 | def deploy(): 266 | code_dir = '/srv/django/myproject' 267 | with settings(warn_only=True): 268 | if run("test -d %s" % code_dir).failed: 269 | run("git clone user@vcshost:/path/to/repo/.git %s" % code_dir) 270 | with cd(code_dir): 271 | run("git pull") 272 | run("touch app.wsgi") 273 | 274 | 就像我们上面调用 `~fabric.operations.local` 一样, `~fabric.operations.run` 也让我们基于 Shell 命令构建干净的 Python 层逻辑。然后这里最有趣的部分是 ``git clone`` :因为我们是用 Git 的 SSH 方法来访问 Git 服务器上的代码库,这意味着我们的远程 `~fabric.operations.run` 调用本身需要身份验证。 275 | 276 | 旧版本的 Fabric(和其他类似的高层次 SSH 库)像在监狱里一样运行远程命令,无法在本地交互。当你很迫切需要输入密码或与远程程序交互时,这就很成问题。 277 | 278 | Fabric 1.0 和后续的版本突破了这个限制,并保证你总是能和另一边对话。让我们看看当我们在一台没有 Git checkout 的新服务器上运行更新后的 ``deploy`` 任务时会发生什么:: 279 | 280 | $ fab deploy 281 | No hosts found. Please specify (single) host string for connection: my_server 282 | [my_server] run: test -d /srv/django/myproject 283 | 284 | Warning: run() encountered an error (return code 1) while executing 'test -d /srv/django/myproject' 285 | 286 | [my_server] run: git clone user@vcshost:/path/to/repo/.git /srv/django/myproject 287 | [my_server] out: Cloning into /srv/django/myproject... 288 | [my_server] out: Password: 289 | [my_server] out: remote: Counting objects: 6698, done. 290 | [my_server] out: remote: Compressing objects: 100% (2237/2237), done. 291 | [my_server] out: remote: Total 6698 (delta 4633), reused 6414 (delta 4412) 292 | [my_server] out: Receiving objects: 100% (6698/6698), 1.28 MiB, done. 293 | [my_server] out: Resolving deltas: 100% (4633/4633), done. 294 | [my_server] out: 295 | [my_server] run: git pull 296 | [my_server] out: Already up-to-date. 297 | [my_server] out: 298 | [my_server] run: touch app.wsgi 299 | 300 | Done. 301 | 302 | 注意那个 ``Password:`` 提示——那就是我们在 Web 服务器上的远程 ``git`` 调用在询问 Git 密码。我们可以在里面输入密码,然后像往常一样继续克隆。 303 | 304 | .. seealso:: :doc:`/usage/interactivity` 305 | 306 | 307 | .. _defining-connections: 308 | 309 | 预先定义连接 310 | ------------------------------- 311 | 312 | 在运行时输入连接信息已经落后太多了,所以 Fabric 提供了一种方便的办法,在你的 fabfile 或命令行中指定。我们不打算在这里完全展开来说,但我们会向你展示最常用的:设置全局主机列表 :ref:`env.hosts ` 。 313 | 314 | :doc:`env ` 是一个全局的类字典对象,驱动着 Fabric 的大部分设置,而且可以带着属性写进去(事实上,前面见过的 `~fabric.context_managers.settings` 是它的一个简单包装)。因此,我们可以在模块层次上,在 fabfile 的顶部附近修改它,就像这样:: 315 | 316 | from __future__ import with_statement 317 | from fabric.api import * 318 | from fabric.contrib.console import confirm 319 | 320 | env.hosts = ['my_server'] 321 | 322 | def test(): 323 | do_test_stuff() 324 | 325 | 当 ``fab`` 加载我们的 fabfile 时,我们对 ``env`` 的修改将被执行,并保存为对设置的修改。最终的结果就如上面所示:我们的 ``deploy`` 任务将在 ``my_server`` 上运行。 326 | 327 | 这也是你如何告诉 Fabric 一次在多台远程服务器上运行的方法:因为 ``env.hosts`` 是一个列表, ``fab`` 对它进行迭代,为每个连接调用指定的任务。 328 | 329 | .. seealso:: :doc:`usage/env`, :ref:`host-lists` 330 | 331 | 332 | 小结 333 | ========== 334 | 335 | 在经过了这么多,我们的完整的 fabfile 文件仍然相当短。下面是它的完整内容:: 336 | 337 | from __future__ import with_statement 338 | from fabric.api import * 339 | from fabric.contrib.console import confirm 340 | 341 | env.hosts = ['my_server'] 342 | 343 | def test(): 344 | with settings(warn_only=True): 345 | result = local('./manage.py test my_app', capture=True) 346 | if result.failed and not confirm("Tests failed. Continue anyway?"): 347 | abort("Aborting at user request.") 348 | 349 | def commit(): 350 | local("git add -p && git commit") 351 | 352 | def push(): 353 | local("git push") 354 | 355 | def prepare_deploy(): 356 | test() 357 | commit() 358 | push() 359 | 360 | def deploy(): 361 | code_dir = '/srv/django/myproject' 362 | with settings(warn_only=True): 363 | if run("test -d %s" % code_dir).failed: 364 | run("git clone user@vcshost:/path/to/repo/.git %s" % code_dir) 365 | with cd(code_dir): 366 | run("git pull") 367 | run("touch app.wsgi") 368 | 369 | 这个 fabfile 使用了 Fabric 的相当一大部分特性集: 370 | 371 | * 定义 fabfile 任务,并用 :doc:`fab ` 运行; 372 | * 用 `~fabric.operations.local` 调用本地 Shell 命令; 373 | * 用 `~fabric.context_managers.settings` 修改环境变量; 374 | * 处理命令故障、提示用户及手工取消; 375 | * 还有定义主机列表和以 `~fabric.operations.run` 运行远程命令。 376 | 377 | 然而,还有更多内容没有在这里覆盖。你还可以看看所有“参见”中提供的链接,和文档内容 :doc:`索引 ` 表。 378 | 379 | 能看到这里真不容易,谢谢! -------------------------------------------------------------------------------- /usage/env.rst: -------------------------------------------------------------------------------- 1 | =================================== 2 | 环境字典 ``env`` 3 | =================================== 4 | 5 | 一个简单但又是 Fabric 组成部分的概念是“环境”:一个 Python 字典子类,被作为组合设置的注册表,和内部任务的共享数据命名空间。 6 | 7 | 环境字典目前被实现为一个全局单例 ``fabric.state.env``,为方便起见,也被包含在 ``fabric.api`` 中。``env`` 中的键也经常被称为“环境变量”。 8 | 9 | 环境与配置 10 | ============================ 11 | 12 | Fabric 的大部分行为可以通过修改 ``env`` 变量来控制,例如 ``env.hosts`` (已经在 :ref:`入门导览 ` 中见过)。其他经常需要修改的环境变量包括: 13 | 14 | * ``user``:Fabric 默认使用你本地用户名去建立 SSH 连接,但如果有必要,你可以用 ``env.user`` 来覆写它。文档 :doc:`execution` 部分也有关于如何针对每个主机设置用户名的信息。 15 | * ``password``:用来显式设置你的默认连接或 sudo 密码。如果没有设置密码或设置了不正确的密码,Fabric 将会提示你输入。 16 | * ``warn_only``:一个布尔值设置,用来表明 Fabric 是否在检测到远程错误时退出。查看 :doc:`execution` 以了解更多关于此行为的信息。 17 | 18 | 还有许多环境变量,可以查看本文档末尾的 :ref:`env-vars` 完整列表。 19 | 20 | 21 | `~fabric.context_managers.settings` 上下文管理器 22 | ------------------------------------------------------- 23 | 24 | 在很多情况下,临时修改 ``env`` 变量以使某些指定的设置只应用到部分代码块是很有用的。Fabric 提供了一个 `~fabric.context_managers.settings` 上下文管理器,它可以接受一个或多个键/值对参数,并用来修改它所包裹的代码块范围内的 ``env``。 25 | 26 | 例如,很多情况下,设置 ``warn_only`` 是很有用的(见下文)。要将它应用到几行代码中,可以用 ``settings(warn_only=True)``。正如下面这个简化版的 ``contrib`` `~fabric.contrib.files.exists` 函数:: 27 | 28 | from fabric.api import settings, run 29 | 30 | def exists(path): 31 | with settings(warn_only=True): 32 | return run('test -e %s' % path) 33 | 34 | 查看 :doc:`../api/core/context_managers` API 文档以了解关于 `~fabric.context_managers.settings` 和其他类似工具的细节。 35 | 36 | 共享状态环境 37 | =========================== 38 | 39 | 前面提到,``env`` 对象简单来说就是个字典子类,所以你的 fabfile 代码也可以在这里保存信息。有些时候,这对于在一次运行的多个任务中保持状态很有用。 40 | 41 | .. note:: 42 | 43 | 这个 ``env`` 是很有历史的:以前的 fabfile 不是纯 Python,所以环境不是在任务间通信的唯一方式。现在,你可以直接调用其他任务或子路径,并保持模块级别的共享状态。 44 | 45 | 在未来的版本,Fabric 将变得线程安全,在这点上,``env`` 将可能会是保持全局状态的唯一简单/安全的方式。 46 | 47 | 其他考虑 48 | ==================== 49 | 50 | 在继承 ``dict`` 的同时,Fabric 的 ``env`` 也作了些修改,以使它的值可以通过属性访问的方式来读/写,这在前文也有所见。换句话来说,``env.host_string`` 和 ``env['host_string']`` 的作用是完全一样的。我们感觉属性访问经常可以节省一些打字,并使代码的可读性更高,所以这也是与 ``env`` 交互的推荐方式。 51 | 52 | 它是个字典的事实也在其他方面很有用,例如用 Python 的基于 ``dict`` 的字符串替代法,可以在你需要在一个字符串中插入多个环境变量值的时候显得尤其方便。使用“普通”的字符串替代法可能就像这样:: 53 | 54 | print("Executing on %s as %s" % (env.host, env.user)) 55 | 56 | 使用字典风格的字符串替代法就更加可读而且简洁:: 57 | 58 | print("Executing on %(host)s as %(user)s" % env) 59 | 60 | .. _env-vars: 61 | 62 | 环境变量完整列表 63 | ===================== 64 | 65 | 以下是所有预定义(或在 Fabric 运行时自己定义)的环境变量的完整列表。它们中的大部分都可以直接操作,但最好还是使用 `~fabric.context_managers`,可以通过 `~fabric.context_managers.settings` 或特定的上下文管理器,如 `~fabric.context_managers.cd`。 66 | 67 | 需注意的是它们中的大部分可以通过 ``fab`` 的命令行参数来设置,更多细节请参考 :doc:`fab`。在下文相应的地方也提供了交叉引用链接。 68 | 69 | .. seealso:: :option:`--set` 70 | 71 | .. _abort-exception: 72 | 73 | ``abort_exception`` 74 | ------------------- 75 | 76 | **默认值:** ``None`` 77 | 78 | 正常情况下,Fabric 执行放弃操作的步骤是先将错误信息打印到标准错误输出,然后调用 ``sys.exit(1)``。这个设置允许你覆写这个默认行为(即 ``env.abort_exception`` 为 ``None`` 时发生的事)。 79 | 80 | 给它一个可调用的对象,它可以接受一个字符串(原来将被打印的错误信息),并返回一个异常实例。这个异常对象将被抛出,以代替(原来的 ``sys.exit`` 执行的) ``SystemExit``。 81 | 82 | 大部分情况下,你可以简单地将它设置为一个异常类,因为它完美符合了上面的描述(可调用、接受一个字符串、返回一个异常实例),例如 ``env.abort_exception = MyExceptionClass``。 83 | 84 | .. _abort-on-prompts: 85 | 86 | ``abort_on_prompts`` 87 | -------------------- 88 | 89 | **默认值:** ``False`` 90 | 91 | 当这个值为 ``True`` 时,Fabric 将以非交互模式运行。此模式下,任何需要提示用户输入(如提示输入密码、询问连接到哪个主机、fabfile 中触发的 `~fabric.operations.prompt` 等等)的时候,都会调用 `~fabric.utils.abort`。这就允许用户确保 Fabric 会话总是清楚地中止,而不是在某些预料之外的情况发生时,仍傻傻地一直在等待用户输入。 92 | 93 | .. versionadded:: 1.1 94 | .. seealso:: :option:`--abort-on-prompts` 95 | 96 | 97 | ``all_hosts`` 98 | ------------- 99 | 100 | **默认值:** ``[]`` 101 | 102 | 由 ``fab`` 设置的当前正在执行的命令的完整主机列表。仅供显示信息。 103 | 104 | .. seealso:: :doc:`execution` 105 | 106 | .. _always-use-pty: 107 | 108 | ``always_use_pty`` 109 | ------------------ 110 | 111 | **默认值:** ``True`` 112 | 113 | 当设置为 ``False`` 时,会使 `~fabric.operations.run`/`~fabric.operations.sudo` 的行为像它们被用 ``pty=False`` 参数调用时一样。 114 | 115 | .. seealso:: :option:`--no-pty` 116 | .. versionadded:: 1.0 117 | 118 | .. _colorize-errors: 119 | 120 | ``colorize_errors`` 121 | ------------------- 122 | 123 | **默认值:** ``False`` 124 | 125 | 当被设置为 ``True`` 时,输出到终端的错误信息会显示成红色,警告信息则显示为洋红色,以使它们更容易被看见。 126 | 127 | .. versionadded:: 1.7 128 | 129 | .. _combine-stderr: 130 | 131 | ``combine_stderr`` 132 | ------------------ 133 | 134 | **默认值:**: ``True`` 135 | 136 | 使 SSH 层合并远程程序的 stdout 和 stderr 流输出,以避免它们在打印时混在一起。查看 :ref:`combine_streams` 以了解为什么需要这个功能,及它的效果是怎样的。 137 | 138 | .. versionadded:: 1.0 139 | 140 | ``command`` 141 | ----------- 142 | 143 | **默认值:** ``None`` 144 | 145 | 由 ``fab`` 设置的当前正在执行的命令名称(例如,执行 ``$ fab task1 task2`` 命令,当执行 ``task1`` 时, ``env.command`` 会被设置为 ``"task1"`` ,然后设置为 ``"task2"`` )。仅供显示信息。 146 | 147 | .. seealso:: :doc:`execution` 148 | 149 | ``command_prefixes`` 150 | -------------------- 151 | 152 | **默认值:** ``[]`` 153 | 154 | 由 `~fabric.context_managers.prefix` 修改,并附加在由 `~fabric.operations.run`/`~fabric.operations.sudo` 执行的命令前面。 155 | 156 | .. versionadded:: 1.0 157 | 158 | .. _command-timeout: 159 | 160 | ``command_timeout`` 161 | ------------------- 162 | 163 | **默认值:** ``None`` 164 | 165 | 远程命令的超时时间,单位为秒。 166 | 167 | .. versionadded:: 1.6 168 | .. seealso:: :option:`--command-timeout` 169 | 170 | .. _connection-attempts: 171 | 172 | ``connection_attempts`` 173 | ----------------------- 174 | 175 | **默认值:** ``1`` 176 | 177 | Fabric 连接一台新服务器的重试次数。出于向后兼容的原因,它的默认值是只尝试连接一次。 178 | 179 | .. versionadded:: 1.4 180 | .. seealso:: :option:`--connection-attempts`, :ref:`timeout` 181 | 182 | ``cwd`` 183 | ------- 184 | 185 | **默认值:** ``''`` 186 | 187 | 当前工作目录,用来为 `~fabric.context_managers.cd` 上下文管理器保持状态。 188 | 189 | .. _dedupe_hosts: 190 | 191 | ``dedupe_hosts`` 192 | ---------------- 193 | 194 | **默认值:** ``True`` 195 | 196 | 去除合并后的主机列表中的重复项,以使任一个主机串只出现一次(例如,当使用 ``@hosts`` + ``@roles`` ,或 ``-H`` 和 197 | ``-R`` 的组合的时候)。 198 | 199 | 当被设置为 ``False`` ,就不会去除重复项,这将允许用户显式地在同一台主机上将一个任务(以串行或并行方式)运行多次。 200 | 201 | .. versionadded:: 1.5 202 | 203 | .. _disable-known-hosts: 204 | 205 | ``disable_known_hosts`` 206 | ----------------------- 207 | 208 | **默认值:** ``False`` 209 | 210 | 如果为 ``True`` SSH 层会跳过用户的 know-hosts 文件不加载。这样可以有效地避免当一个“已知主机”改变了 key、但仍然有效(云服务器,例如 EC2)时的异常。 211 | 212 | .. seealso:: :option:`--disable-known-hosts <-D>`, :doc:`ssh` 213 | 214 | 215 | .. _eagerly-disconnect: 216 | 217 | ``eagerly_disconnect`` 218 | ---------------------- 219 | 220 | **默认值:** ``False`` 221 | 222 | 当它为 ``True`` 时, ``fab`` 会在每个单独的任务完成后关闭连接,而不是在整个运行结束后。这可以帮助避免堆积大量无用的网络会话、或因每个进程可打开的文件或网络硬件的限制而导致问题。 223 | 224 | .. note:: 225 | 当打开这个设置时,断开连接的信息会遍布于你的输出信息始终,而不是在最后。以后的版本可能会改进这一点。 226 | 227 | .. _effective_roles: 228 | 229 | ``effective_roles`` 230 | ------------------- 231 | 232 | **默认值:** ``[]`` 233 | 234 | 由 ``fab`` 设置的当前正在执行的命令的角色列表。仅供显示信息。 235 | 236 | .. seealso:: :doc:`execution` 237 | 238 | .. _exclude-hosts: 239 | 240 | ``exclude_hosts`` 241 | ----------------- 242 | 243 | **默认值:** ``[]`` 244 | 245 | 指定一个主机串列表,以在 ``fab`` 执行过程中 :ref:`skipped over ` 。通常通过 :option:`--exclude-hosts/-x <-x>` 来设置。 246 | 247 | .. versionadded:: 1.1 248 | 249 | 250 | ``fabfile`` 251 | ----------- 252 | 253 | **默认值:** ``fabfile.py`` 254 | 255 | 当 ``fab`` 加载 fabfile 时查找的文件名。要指定一个特定的 fabfile 文件,需要使用该文件的完整路径。显然,不可能在 fabfile 中设置这个参数,但它可以在一个 .fabricrc 文件设置,或通过命令行参数设置。 256 | 257 | .. seealso:: :option:`--fabfile <-f>`, :doc:`fab` 258 | 259 | 260 | .. _gateway: 261 | 262 | ``gateway`` 263 | ----------- 264 | 265 | **默认值:** ``None`` 266 | 267 | 允许通过指定主机创建 SSH 驱动的网关。它的值应该是一个普通的 Fabric 主机串,和在 :ref:`env.host_string ` 中使用的一样。当它被设置时,新创建的连接将会通过这个远程 SSH 连接到最终的目的地。 268 | 269 | .. versionadded:: 1.5 270 | 271 | .. seealso:: :option:`--gateway <-g>` 272 | 273 | 274 | .. _host_string: 275 | 276 | ``host_string`` 277 | --------------- 278 | 279 | **默认值:** ``None`` 280 | 281 | 定义了 Fabric 在执行 `~fabric.operations.run` 、 `~fabric.operations.put` 等命令时使用的用户/主机/端口。它可以由 ``fab`` 在与已设置的主机列表交互时设置,也可以在将 Fabric 作为一个库使用时手工设置。 282 | 283 | .. seealso:: :doc:`execution` 284 | 285 | 286 | .. _forward-agent: 287 | 288 | ``forward_agent`` 289 | -------------------- 290 | 291 | **默认值:** ``False`` 292 | 293 | If ``True``, enables forwarding of your local SSH agent to the remote end. 294 | 295 | .. versionadded:: 1.4 296 | 297 | .. seealso:: :option:`--forward-agent <-A>` 298 | 299 | 300 | ``host`` 301 | -------- 302 | 303 | **默认值:** ``None`` 304 | 305 | Set to the hostname part of ``env.host_string`` by ``fab``. For informational 306 | purposes only. 307 | 308 | .. _hosts: 309 | 310 | ``hosts`` 311 | --------- 312 | 313 | **默认值:** ``[]`` 314 | 315 | The global host list used when composing per-task host lists. 316 | 317 | .. seealso:: :option:`--hosts <-H>`, :doc:`execution` 318 | 319 | .. _keepalive: 320 | 321 | ``keepalive`` 322 | ------------- 323 | 324 | **默认值:** ``0`` (i.e. no keepalive) 325 | 326 | An integer specifying an SSH keepalive interval to use; basically maps to the 327 | SSH config option ``ClientAliveInterval``. Useful if you find connections are 328 | timing out due to meddlesome network hardware or what have you. 329 | 330 | .. seealso:: :option:`--keepalive` 331 | .. versionadded:: 1.1 332 | 333 | 334 | .. _key: 335 | 336 | ``key`` 337 | ---------------- 338 | 339 | **默认值:** ``None`` 340 | 341 | A string, or file-like object, containing an SSH key; used during connection 342 | authentication. 343 | 344 | .. note:: 345 | The most common method for using SSH keys is to set :ref:`key-filename`. 346 | 347 | .. versionadded:: 1.7 348 | 349 | 350 | .. _key-filename: 351 | 352 | ``key_filename`` 353 | ---------------- 354 | 355 | **默认值:** ``None`` 356 | 357 | May be a string or list of strings, referencing file paths to SSH key files to 358 | try when connecting. Passed through directly to the SSH layer. May be 359 | set/appended to with :option:`-i`. 360 | 361 | .. seealso:: `Paramiko's documentation for SSHClient.connect() `_ 362 | 363 | .. _env-linewise: 364 | 365 | ``linewise`` 366 | ------------ 367 | 368 | **默认值:** ``False`` 369 | 370 | Forces buffering by line instead of by character/byte, typically when running 371 | in parallel mode. May be activated via :option:`--linewise`. This option is 372 | implied by :ref:`env.parallel ` -- even if ``linewise`` is False, 373 | if ``parallel`` is True then linewise behavior will occur. 374 | 375 | .. seealso:: :ref:`linewise-output` 376 | 377 | .. versionadded:: 1.3 378 | 379 | 380 | .. _local-user: 381 | 382 | ``local_user`` 383 | -------------- 384 | 385 | A read-only value containing the local system username. This is the same value 386 | as :ref:`user`'s initial value, but whereas :ref:`user` may be altered by CLI 387 | arguments, Python code or specific host strings, :ref:`local-user` will always 388 | contain the same value. 389 | 390 | .. _no_agent: 391 | 392 | ``no_agent`` 393 | ------------ 394 | 395 | **默认值:** ``False`` 396 | 397 | If ``True``, will tell the SSH layer not to seek out running SSH agents when 398 | using key-based authentication. 399 | 400 | .. versionadded:: 0.9.1 401 | .. seealso:: :option:`--no_agent <-a>` 402 | 403 | .. _no_keys: 404 | 405 | ``no_keys`` 406 | ------------------ 407 | 408 | **默认值:** ``False`` 409 | 410 | If ``True``, will tell the SSH layer not to load any private key files from 411 | one's ``$HOME/.ssh/`` folder. (Key files explicitly loaded via ``fab -i`` will 412 | still be used, of course.) 413 | 414 | .. versionadded:: 0.9.1 415 | .. seealso:: :option:`-k` 416 | 417 | .. _env-parallel: 418 | 419 | ``parallel`` 420 | ------------------- 421 | 422 | **默认值:** ``False`` 423 | 424 | When ``True``, forces all tasks to run in parallel. Implies :ref:`env.linewise 425 | `. 426 | 427 | .. versionadded:: 1.3 428 | .. seealso:: :option:`--parallel <-P>`, :doc:`parallel` 429 | 430 | .. _password: 431 | 432 | ``password`` 433 | ------------ 434 | 435 | **默认值:** ``None`` 436 | 437 | The default password used by the SSH layer when connecting to remote hosts, 438 | **and/or** when answering `~fabric.operations.sudo` prompts. 439 | 440 | .. seealso:: :option:`--initial-password-prompt <-I>`, :ref:`env.passwords `, :ref:`password-management` 441 | 442 | .. _passwords: 443 | 444 | ``passwords`` 445 | ------------- 446 | 447 | **默认值:** ``{}`` 448 | 449 | This dictionary is largely for internal use, and is filled automatically as a 450 | per-host-string password cache. Keys are full :ref:`host strings 451 | ` and values are passwords (strings). 452 | 453 | .. seealso:: :ref:`password-management` 454 | 455 | .. versionadded:: 1.0 456 | 457 | 458 | .. _env-path: 459 | 460 | ``path`` 461 | -------- 462 | 463 | **默认值:** ``''`` 464 | 465 | Used to set the ``$PATH`` shell environment variable when executing commands in 466 | `~fabric.operations.run`/`~fabric.operations.sudo`/`~fabric.operations.local`. 467 | It is recommended to use the `~fabric.context_managers.path` context manager 468 | for managing this value instead of setting it directly. 469 | 470 | .. versionadded:: 1.0 471 | 472 | 473 | .. _pool-size: 474 | 475 | ``pool_size`` 476 | ------------- 477 | 478 | **默认值:** ``0`` 479 | 480 | Sets the number of concurrent processes to use when executing tasks in parallel. 481 | 482 | .. versionadded:: 1.3 483 | .. seealso:: :option:`--pool-size <-z>`, :doc:`parallel` 484 | 485 | .. _prompts: 486 | 487 | ``prompts`` 488 | ------------- 489 | 490 | **默认值:** ``{}`` 491 | 492 | The ``prompts`` dictionary allows users to control interactive prompts. If a 493 | key in the dictionary is found in a command's standard output stream, Fabric 494 | will automatically answer with the corresponding dictionary value. 495 | 496 | .. versionadded:: 1.9 497 | 498 | .. _port: 499 | 500 | ``port`` 501 | -------- 502 | 503 | **默认值:** ``None`` 504 | 505 | Set to the port part of ``env.host_string`` by ``fab`` when iterating over a 506 | host list. May also be used to specify a default port. 507 | 508 | .. _real-fabfile: 509 | 510 | ``real_fabfile`` 511 | ---------------- 512 | 513 | **默认值:** ``None`` 514 | 515 | Set by ``fab`` with the path to the fabfile it has loaded up, if it got that 516 | far. For informational purposes only. 517 | 518 | .. seealso:: :doc:`fab` 519 | 520 | 521 | .. _remote-interrupt: 522 | 523 | ``remote_interrupt`` 524 | -------------------- 525 | 526 | **默认值:** ``None`` 527 | 528 | Controls whether Ctrl-C triggers an interrupt remotely or is captured locally, 529 | as follows: 530 | 531 | * ``None`` (the default): only `~fabric.operations.open_shell` will exhibit 532 | remote interrupt behavior, and 533 | `~fabric.operations.run`/`~fabric.operations.sudo` will capture interrupts 534 | locally. 535 | * ``False``: even `~fabric.operations.open_shell` captures locally. 536 | * ``True``: all functions will send the interrupt to the remote end. 537 | 538 | .. versionadded:: 1.6 539 | 540 | 541 | .. _rcfile: 542 | 543 | ``rcfile`` 544 | ---------- 545 | 546 | **默认值:** ``$HOME/.fabricrc`` 547 | 548 | Path used when loading Fabric's local settings file. 549 | 550 | .. seealso:: :option:`--config <-c>`, :doc:`fab` 551 | 552 | .. _reject-unknown-hosts: 553 | 554 | ``reject_unknown_hosts`` 555 | ------------------------ 556 | 557 | **默认值:** ``False`` 558 | 559 | If ``True``, the SSH layer will raise an exception when connecting to hosts not 560 | listed in the user's known-hosts file. 561 | 562 | .. seealso:: :option:`--reject-unknown-hosts <-r>`, :doc:`ssh` 563 | 564 | .. _system-known-hosts: 565 | 566 | ``system_known_hosts`` 567 | ------------------------ 568 | 569 | **默认值:** ``None`` 570 | 571 | If set, should be the path to a :file:`known_hosts` file. The SSH layer will 572 | read this file before reading the user's known-hosts file. 573 | 574 | .. seealso:: :doc:`ssh` 575 | 576 | ``roledefs`` 577 | ------------ 578 | 579 | **默认值:** ``{}`` 580 | 581 | Dictionary defining role name to host list mappings. 582 | 583 | .. seealso:: :doc:`execution` 584 | 585 | .. _roles: 586 | 587 | ``roles`` 588 | --------- 589 | 590 | **默认值:** ``[]`` 591 | 592 | The global role list used when composing per-task host lists. 593 | 594 | .. seealso:: :option:`--roles <-R>`, :doc:`execution` 595 | 596 | .. _shell: 597 | 598 | ``shell`` 599 | --------- 600 | 601 | **默认值:** ``/bin/bash -l -c`` 602 | 603 | Value used as shell wrapper when executing commands with e.g. 604 | `~fabric.operations.run`. Must be able to exist in the form `` 605 | ""`` -- e.g. the default uses Bash's ``-c`` option which 606 | takes a command string as its value. 607 | 608 | .. seealso:: :option:`--shell <-s>`, 609 | :ref:`FAQ on bash as default shell `, :doc:`execution` 610 | 611 | .. _skip-bad-hosts: 612 | 613 | ``skip_bad_hosts`` 614 | ------------------ 615 | 616 | **默认值:** ``False`` 617 | 618 | If ``True``, causes ``fab`` (or non-``fab`` use of `~fabric.tasks.execute`) to skip over hosts it can't connect to. 619 | 620 | .. versionadded:: 1.4 621 | .. seealso:: 622 | :option:`--skip-bad-hosts`, :ref:`excluding-hosts`, :doc:`execution` 623 | 624 | 625 | .. _ssh-config-path: 626 | 627 | ``ssh_config_path`` 628 | ------------------- 629 | 630 | **默认值:** ``$HOME/.ssh/config`` 631 | 632 | Allows specification of an alternate SSH configuration file path. 633 | 634 | .. versionadded:: 1.4 635 | .. seealso:: :option:`--ssh-config-path`, :ref:`ssh-config` 636 | 637 | ``ok_ret_codes`` 638 | ------------------------ 639 | 640 | **默认值:** ``[0]`` 641 | 642 | Return codes in this list are used to determine whether calls to 643 | `~fabric.operations.run`/`~fabric.operations.sudo`/`~fabric.operations.sudo` 644 | are considered successful. 645 | 646 | .. versionadded:: 1.6 647 | 648 | .. _sudo_prefix: 649 | 650 | ``sudo_prefix`` 651 | --------------- 652 | 653 | **默认值:** ``"sudo -S -p '%(sudo_prompt)s' " % env`` 654 | 655 | The actual ``sudo`` command prefixed onto `~fabric.operations.sudo` calls' 656 | command strings. Users who do not have ``sudo`` on their default remote 657 | ``$PATH``, or who need to make other changes (such as removing the ``-p`` when 658 | passwordless sudo is in effect) may find changing this useful. 659 | 660 | .. seealso:: 661 | 662 | The `~fabric.operations.sudo` operation; :ref:`env.sudo_prompt 663 | ` 664 | 665 | .. _sudo_prompt: 666 | 667 | ``sudo_prompt`` 668 | --------------- 669 | 670 | **默认值:** ``"sudo password:"`` 671 | 672 | Passed to the ``sudo`` program on remote systems so that Fabric may correctly 673 | identify its password prompt. 674 | 675 | .. seealso:: 676 | 677 | The `~fabric.operations.sudo` operation; :ref:`env.sudo_prefix 678 | ` 679 | 680 | .. _sudo_user: 681 | 682 | ``sudo_user`` 683 | ------------- 684 | 685 | **默认值:** ``None`` 686 | 687 | Used as a fallback value for `~fabric.operations.sudo`'s ``user`` argument if 688 | none is given. Useful in combination with `~fabric.context_managers.settings`. 689 | 690 | .. seealso:: `~fabric.operations.sudo` 691 | 692 | .. _env-tasks: 693 | 694 | ``tasks`` 695 | ------------- 696 | 697 | **默认值:** ``[]`` 698 | 699 | Set by ``fab`` to the full tasks list to be executed for the currently 700 | executing command. For informational purposes only. 701 | 702 | .. seealso:: :doc:`execution` 703 | 704 | .. _timeout: 705 | 706 | ``timeout`` 707 | ----------- 708 | 709 | **默认值:** ``10`` 710 | 711 | Network connection timeout, in seconds. 712 | 713 | .. versionadded:: 1.4 714 | .. seealso:: :option:`--timeout`, :ref:`connection-attempts` 715 | 716 | ``use_shell`` 717 | ------------- 718 | 719 | **默认值:** ``True`` 720 | 721 | Global setting which acts like the ``shell`` argument to 722 | `~fabric.operations.run`/`~fabric.operations.sudo`: if it is set to ``False``, 723 | operations will not wrap executed commands in ``env.shell``. 724 | 725 | 726 | .. _use-ssh-config: 727 | 728 | ``use_ssh_config`` 729 | ------------------ 730 | 731 | **默认值:** ``False`` 732 | 733 | Set to ``True`` to cause Fabric to load your local SSH config file. 734 | 735 | .. versionadded:: 1.4 736 | .. seealso:: :ref:`ssh-config` 737 | 738 | 739 | .. _user: 740 | 741 | ``user`` 742 | -------- 743 | 744 | **默认值:** User's local username 745 | 746 | The username used by the SSH layer when connecting to remote hosts. May be set 747 | globally, and will be used when not otherwise explicitly set in host strings. 748 | However, when explicitly given in such a manner, this variable will be 749 | temporarily overwritten with the current value -- i.e. it will always display 750 | the user currently being connected as. 751 | 752 | To illustrate this, a fabfile:: 753 | 754 | from fabric.api import env, run 755 | 756 | env.user = 'implicit_user' 757 | env.hosts = ['host1', 'explicit_user@host2', 'host3'] 758 | 759 | def print_user(): 760 | with hide('running'): 761 | run('echo "%(user)s"' % env) 762 | 763 | and its use:: 764 | 765 | $ fab print_user 766 | 767 | [host1] out: implicit_user 768 | [explicit_user@host2] out: explicit_user 769 | [host3] out: implicit_user 770 | 771 | Done. 772 | Disconnecting from host1... done. 773 | Disconnecting from host2... done. 774 | Disconnecting from host3... done. 775 | 776 | As you can see, during execution on ``host2``, ``env.user`` was set to 777 | ``"explicit_user"``, but was restored to its previous value 778 | (``"implicit_user"``) afterwards. 779 | 780 | .. note:: 781 | 782 | ``env.user`` is currently somewhat confusing (it's used for configuration 783 | **and** informational purposes) so expect this to change in the future -- 784 | the informational aspect will likely be broken out into a separate env 785 | variable. 786 | 787 | .. seealso:: :doc:`execution`, :option:`--user <-u>` 788 | 789 | ``version`` 790 | ----------- 791 | 792 | **默认值:** current Fabric version string 793 | 794 | Mostly for informational purposes. Modification is not recommended, but 795 | probably won't break anything either. 796 | 797 | .. seealso:: :option:`--version <-V>` 798 | 799 | .. _warn_only: 800 | 801 | ``warn_only`` 802 | ------------- 803 | 804 | **默认值:** ``False`` 805 | 806 | Specifies whether or not to warn, instead of abort, when 807 | `~fabric.operations.run`/`~fabric.operations.sudo`/`~fabric.operations.local` 808 | encounter error conditions. 809 | 810 | .. seealso:: :option:`--warn-only <-w>`, :doc:`execution` 811 | -------------------------------------------------------------------------------- /usage/execution.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Execution model 3 | =============== 4 | 5 | If you've read the :doc:`../tutorial`, you should already be familiar with how 6 | Fabric operates in the base case (a single task on a single host.) However, in 7 | many situations you'll find yourself wanting to execute multiple tasks and/or 8 | on multiple hosts. Perhaps you want to split a big task into smaller reusable 9 | parts, or crawl a collection of servers looking for an old user to remove. Such 10 | a scenario requires specific rules for when and how tasks are executed. 11 | 12 | This document explores Fabric's execution model, including the main execution 13 | loop, how to define host lists, how connections are made, and so forth. 14 | 15 | 16 | .. _execution-strategy: 17 | 18 | Execution strategy 19 | ================== 20 | 21 | Fabric defaults to a single, serial execution method, though there is an 22 | alternative parallel mode available as of Fabric 1.3 (see 23 | :doc:`/usage/parallel`). This default behavior is as follows: 24 | 25 | * A list of tasks is created. Currently this list is simply the arguments given 26 | to :doc:`fab `, preserving the order given. 27 | * For each task, a task-specific host list is generated from various 28 | sources (see :ref:`host-lists` below for details.) 29 | * The task list is walked through in order, and each task is run once per host 30 | in its host list. 31 | * Tasks with no hosts in their host list are considered local-only, and will 32 | always run once and only once. 33 | 34 | Thus, given the following fabfile:: 35 | 36 | from fabric.api import run, env 37 | 38 | env.hosts = ['host1', 'host2'] 39 | 40 | def taskA(): 41 | run('ls') 42 | 43 | def taskB(): 44 | run('whoami') 45 | 46 | and the following invocation:: 47 | 48 | $ fab taskA taskB 49 | 50 | you will see that Fabric performs the following: 51 | 52 | * ``taskA`` executed on ``host1`` 53 | * ``taskA`` executed on ``host2`` 54 | * ``taskB`` executed on ``host1`` 55 | * ``taskB`` executed on ``host2`` 56 | 57 | While this approach is simplistic, it allows for a straightforward composition 58 | of task functions, and (unlike tools which push the multi-host functionality 59 | down to the individual function calls) enables shell script-like logic where 60 | you may introspect the output or return code of a given command and decide what 61 | to do next. 62 | 63 | 64 | Defining tasks 65 | ============== 66 | 67 | For details on what constitutes a Fabric task and how to organize them, please see :doc:`/usage/tasks`. 68 | 69 | 70 | Defining host lists 71 | =================== 72 | 73 | Unless you're using Fabric as a simple build system (which is possible, but not 74 | the primary use-case) having tasks won't do you any good without the ability to 75 | specify remote hosts on which to execute them. There are a number of ways to do 76 | so, with scopes varying from global to per-task, and it's possible mix and 77 | match as needed. 78 | 79 | .. _host-strings: 80 | 81 | Hosts 82 | ----- 83 | 84 | Hosts, in this context, refer to what are also called "host strings": Python 85 | strings specifying a username, hostname and port combination, in the form of 86 | ``username@hostname:port``. User and/or port (and the associated ``@`` or 87 | ``:``) may be omitted, and will be filled by the executing user's local 88 | username, and/or port 22, respectively. Thus, ``admin@foo.com:222``, 89 | ``deploy@website`` and ``nameserver1`` could all be valid host strings. 90 | 91 | IPv6 address notation is also supported, for example ``::1``, ``[::1]:1222``, 92 | ``user@2001:db8::1`` or ``user@[2001:db8::1]:1222``. Square brackets 93 | are necessary only to separate the address from the port number. If no 94 | port number is used, the brackets are optional. Also if host string is 95 | specified via command-line argument, it may be necessary to escape 96 | brackets in some shells. 97 | 98 | .. note:: 99 | The user/hostname split occurs at the last ``@`` found, so e.g. email 100 | address usernames are valid and will be parsed correctly. 101 | 102 | During execution, Fabric normalizes the host strings given and then stores each 103 | part (username/hostname/port) in the environment dictionary, for both its use 104 | and for tasks to reference if the need arises. See :doc:`env` for details. 105 | 106 | .. _execution-roles: 107 | 108 | Roles 109 | ----- 110 | 111 | Host strings map to single hosts, but sometimes it's useful to arrange hosts in 112 | groups. Perhaps you have a number of Web servers behind a load balancer and 113 | want to update all of them, or want to run a task on "all client servers". 114 | Roles provide a way of defining strings which correspond to lists of host 115 | strings, and can then be specified instead of writing out the entire list every 116 | time. 117 | 118 | This mapping is defined as a dictionary, ``env.roledefs``, which must be 119 | modified by a fabfile in order to be used. A simple example:: 120 | 121 | from fabric.api import env 122 | 123 | env.roledefs['webservers'] = ['www1', 'www2', 'www3'] 124 | 125 | Since ``env.roledefs`` is naturally empty by default, you may also opt to 126 | re-assign to it without fear of losing any information (provided you aren't 127 | loading other fabfiles which also modify it, of course):: 128 | 129 | from fabric.api import env 130 | 131 | env.roledefs = { 132 | 'web': ['www1', 'www2', 'www3'], 133 | 'dns': ['ns1', 'ns2'] 134 | } 135 | 136 | In addition to list/iterable object types, the values in ``env.roledefs`` may 137 | be callables, and will thus be called when looked up when tasks are run instead 138 | of at module load time. (For example, you could connect to remote servers 139 | to obtain role definitions, and not worry about causing delays at fabfile load 140 | time when calling e.g. ``fab --list``.) 141 | 142 | Use of roles is not required in any way -- it's simply a convenience in 143 | situations where you have common groupings of servers. 144 | 145 | .. versionchanged:: 0.9.2 146 | Added ability to use callables as ``roledefs`` values. 147 | 148 | .. _host-lists: 149 | 150 | How host lists are constructed 151 | ------------------------------ 152 | 153 | There are a number of ways to specify host lists, either globally or per-task, 154 | and generally these methods override one another instead of merging together 155 | (though this may change in future releases.) Each such method is typically 156 | split into two parts, one for hosts and one for roles. 157 | 158 | Globally, via ``env`` 159 | ~~~~~~~~~~~~~~~~~~~~~ 160 | 161 | The most common method of setting hosts or roles is by modifying two key-value 162 | pairs in the environment dictionary, :doc:`env `: ``hosts`` and ``roles``. 163 | The value of these variables is checked at runtime, while constructing each 164 | tasks's host list. 165 | 166 | Thus, they may be set at module level, which will take effect when the fabfile 167 | is imported:: 168 | 169 | from fabric.api import env, run 170 | 171 | env.hosts = ['host1', 'host2'] 172 | 173 | def mytask(): 174 | run('ls /var/www') 175 | 176 | Such a fabfile, run simply as ``fab mytask``, will run ``mytask`` on ``host1`` 177 | followed by ``host2``. 178 | 179 | Since the env vars are checked for *each* task, this means that if you have the 180 | need, you can actually modify ``env`` in one task and it will affect all 181 | following tasks:: 182 | 183 | from fabric.api import env, run 184 | 185 | def set_hosts(): 186 | env.hosts = ['host1', 'host2'] 187 | 188 | def mytask(): 189 | run('ls /var/www') 190 | 191 | When run as ``fab set_hosts mytask``, ``set_hosts`` is a "local" task -- its 192 | own host list is empty -- but ``mytask`` will again run on the two hosts given. 193 | 194 | .. note:: 195 | 196 | This technique used to be a common way of creating fake "roles", but is 197 | less necessary now that roles are fully implemented. It may still be useful 198 | in some situations, however. 199 | 200 | Alongside ``env.hosts`` is ``env.roles`` (not to be confused with 201 | ``env.roledefs``!) which, if given, will be taken as a list of role names to 202 | look up in ``env.roledefs``. 203 | 204 | Globally, via the command line 205 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 206 | 207 | In addition to modifying ``env.hosts``, ``env.roles``, and 208 | ``env.exclude_hosts`` at the module level, you may define them by passing 209 | comma-separated string arguments to the command-line switches 210 | :option:`--hosts/-H <-H>` and :option:`--roles/-R <-R>`, e.g.:: 211 | 212 | $ fab -H host1,host2 mytask 213 | 214 | Such an invocation is directly equivalent to ``env.hosts = ['host1', 'host2']`` 215 | -- the argument parser knows to look for these arguments and will modify 216 | ``env`` at parse time. 217 | 218 | .. note:: 219 | 220 | It's possible, and in fact common, to use these switches to set only a 221 | single host or role. Fabric simply calls ``string.split(',')`` on the given 222 | string, so a string with no commas turns into a single-item list. 223 | 224 | It is important to know that these command-line switches are interpreted 225 | **before** your fabfile is loaded: any reassignment to ``env.hosts`` or 226 | ``env.roles`` in your fabfile will overwrite them. 227 | 228 | If you wish to nondestructively merge the command-line hosts with your 229 | fabfile-defined ones, make sure your fabfile uses ``env.hosts.extend()`` 230 | instead:: 231 | 232 | from fabric.api import env, run 233 | 234 | env.hosts.extend(['host3', 'host4']) 235 | 236 | def mytask(): 237 | run('ls /var/www') 238 | 239 | When this fabfile is run as ``fab -H host1,host2 mytask``, ``env.hosts`` will 240 | then contain ``['host1', 'host2', 'host3', 'host4']`` at the time that 241 | ``mytask`` is executed. 242 | 243 | .. note:: 244 | 245 | ``env.hosts`` is simply a Python list object -- so you may use 246 | ``env.hosts.append()`` or any other such method you wish. 247 | 248 | .. _hosts-per-task-cli: 249 | 250 | Per-task, via the command line 251 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 252 | 253 | Globally setting host lists only works if you want all your tasks to run on the 254 | same host list all the time. This isn't always true, so Fabric provides a few 255 | ways to be more granular and specify host lists which apply to a single task 256 | only. The first of these uses task arguments. 257 | 258 | As outlined in :doc:`fab`, it's possible to specify per-task arguments via a 259 | special command-line syntax. In addition to naming actual arguments to your 260 | task function, this may be used to set the ``host``, ``hosts``, ``role`` or 261 | ``roles`` "arguments", which are interpreted by Fabric when building host lists 262 | (and removed from the arguments passed to the task itself.) 263 | 264 | .. note:: 265 | 266 | Since commas are already used to separate task arguments from one another, 267 | semicolons must be used in the ``hosts`` or ``roles`` arguments to 268 | delineate individual host strings or role names. Furthermore, the argument 269 | must be quoted to prevent your shell from interpreting the semicolons. 270 | 271 | Take the below fabfile, which is the same one we've been using, but which 272 | doesn't define any host info at all:: 273 | 274 | from fabric.api import run 275 | 276 | def mytask(): 277 | run('ls /var/www') 278 | 279 | To specify per-task hosts for ``mytask``, execute it like so:: 280 | 281 | $ fab mytask:hosts="host1;host2" 282 | 283 | This will override any other host list and ensure ``mytask`` always runs on 284 | just those two hosts. 285 | 286 | Per-task, via decorators 287 | ~~~~~~~~~~~~~~~~~~~~~~~~ 288 | 289 | If a given task should always run on a predetermined host list, you may wish to 290 | specify this in your fabfile itself. This can be done by decorating a task 291 | function with the `~fabric.decorators.hosts` or `~fabric.decorators.roles` 292 | decorators. These decorators take a variable argument list, like so:: 293 | 294 | from fabric.api import hosts, run 295 | 296 | @hosts('host1', 'host2') 297 | def mytask(): 298 | run('ls /var/www') 299 | 300 | They will also take an single iterable argument, e.g.:: 301 | 302 | my_hosts = ('host1', 'host2') 303 | @hosts(my_hosts) 304 | def mytask(): 305 | # ... 306 | 307 | When used, these decorators override any checks of ``env`` for that particular 308 | task's host list (though ``env`` is not modified in any way -- it is simply 309 | ignored.) Thus, even if the above fabfile had defined ``env.hosts`` or the call 310 | to :doc:`fab ` uses :option:`--hosts/-H <-H>`, ``mytask`` would still run 311 | on a host list of ``['host1', 'host2']``. 312 | 313 | However, decorator host lists do **not** override per-task command-line 314 | arguments, as given in the previous section. 315 | 316 | Order of precedence 317 | ~~~~~~~~~~~~~~~~~~~ 318 | 319 | We've been pointing out which methods of setting host lists trump the others, 320 | as we've gone along. However, to make things clearer, here's a quick breakdown: 321 | 322 | * Per-task, command-line host lists (``fab mytask:host=host1``) override 323 | absolutely everything else. 324 | * Per-task, decorator-specified host lists (``@hosts('host1')``) override the 325 | ``env`` variables. 326 | * Globally specified host lists set in the fabfile (``env.hosts = ['host1']``) 327 | *can* override such lists set on the command-line, but only if you're not 328 | careful (or want them to.) 329 | * Globally specified host lists set on the command-line (``--hosts=host1``) 330 | will initialize the ``env`` variables, but that's it. 331 | 332 | This logic may change slightly in the future to be more consistent (e.g. 333 | having :option:`--hosts <-H>` somehow take precedence over ``env.hosts`` in the 334 | same way that command-line per-task lists trump in-code ones) but only in a 335 | backwards-incompatible release. 336 | 337 | .. _combining-host-lists: 338 | 339 | Combining host lists 340 | -------------------- 341 | 342 | There is no "unionizing" of hosts between the various sources mentioned in 343 | :ref:`host-lists`. If ``env.hosts`` is set to ``['host1', 'host2', 'host3']``, 344 | and a per-function (e.g. via `~fabric.decorators.hosts`) host list is set to 345 | just ``['host2', 'host3']``, that function will **not** execute on ``host1``, 346 | because the per-task decorator host list takes precedence. 347 | 348 | However, for each given source, if both roles **and** hosts are specified, they 349 | will be merged together into a single host list. Take, for example, this 350 | fabfile where both of the decorators are used:: 351 | 352 | from fabric.api import env, hosts, roles, run 353 | 354 | env.roledefs = {'role1': ['b', 'c']} 355 | 356 | @hosts('a', 'b') 357 | @roles('role1') 358 | def mytask(): 359 | run('ls /var/www') 360 | 361 | Assuming no command-line hosts or roles are given when ``mytask`` is executed, 362 | this fabfile will call ``mytask`` on a host list of ``['a', 'b', 'c']`` -- the 363 | union of ``role1`` and the contents of the `~fabric.decorators.hosts` call. 364 | 365 | 366 | .. _deduplication: 367 | 368 | Host list deduplication 369 | ----------------------- 370 | 371 | By default, to support :ref:`combining-host-lists`, Fabric deduplicates the 372 | final host list so any given host string is only present once. However, this 373 | prevents explicit/intentional running of a task multiple times on the same 374 | target host, which is sometimes useful. 375 | 376 | To turn off deduplication, set :ref:`env.dedupe_hosts ` to 377 | ``False``. 378 | 379 | 380 | .. _excluding-hosts: 381 | 382 | Excluding specific hosts 383 | ------------------------ 384 | 385 | At times, it is useful to exclude one or more specific hosts, e.g. to override 386 | a few bad or otherwise undesirable hosts which are pulled in from a role or an 387 | autogenerated host list. 388 | 389 | .. note:: 390 | As of Fabric 1.4, you may wish to use :ref:`skip-bad-hosts` instead, which 391 | automatically skips over any unreachable hosts. 392 | 393 | Host exclusion may be accomplished globally with :option:`--exclude-hosts/-x 394 | <-x>`:: 395 | 396 | $ fab -R myrole -x host2,host5 mytask 397 | 398 | If ``myrole`` was defined as ``['host1', 'host2', ..., 'host15']``, the above 399 | invocation would run with an effective host list of ``['host1', 'host3', 400 | 'host4', 'host6', ..., 'host15']``. 401 | 402 | .. note:: 403 | Using this option does not modify ``env.hosts`` -- it only causes the 404 | main execution loop to skip the requested hosts. 405 | 406 | Exclusions may be specified per-task by using an extra ``exclude_hosts`` kwarg, 407 | which is implemented similarly to the abovementioned ``hosts`` and ``roles`` 408 | per-task kwargs, in that it is stripped from the actual task invocation. This 409 | example would have the same result as the global exclude above:: 410 | 411 | $ fab mytask:roles=myrole,exclude_hosts="host2;host5" 412 | 413 | Note that the host list is semicolon-separated, just as with the ``hosts`` 414 | per-task argument. 415 | 416 | Combining exclusions 417 | ~~~~~~~~~~~~~~~~~~~~ 418 | 419 | Host exclusion lists, like host lists themselves, are not merged together 420 | across the different "levels" they can be declared in. For example, a global 421 | ``-x`` option will not affect a per-task host list set with a decorator or 422 | keyword argument, nor will per-task ``exclude_hosts`` keyword arguments affect 423 | a global ``-H`` list. 424 | 425 | There is one minor exception to this rule, namely that CLI-level keyword 426 | arguments (``mytask:exclude_hosts=x,y``) **will** be taken into account when 427 | examining host lists set via ``@hosts`` or ``@roles``. Thus a task function 428 | decorated with ``@hosts('host1', 'host2')`` executed as ``fab 429 | taskname:exclude_hosts=host2`` will only run on ``host1``. 430 | 431 | As with the host list merging, this functionality is currently limited (partly 432 | to keep the implementation simple) and may be expanded in future releases. 433 | 434 | 435 | .. _execute: 436 | 437 | Intelligently executing tasks with ``execute`` 438 | ============================================== 439 | 440 | .. versionadded:: 1.3 441 | 442 | Most of the information here involves "top level" tasks executed via :doc:`fab 443 | `, such as the first example where we called ``fab taskA taskB``. 444 | However, it's often convenient to wrap up multi-task invocations like this into 445 | their own, "meta" tasks. 446 | 447 | Prior to Fabric 1.3, this had to be done by hand, as outlined in 448 | :doc:`/usage/library`. Fabric's design eschews magical behavior, so simply 449 | *calling* a task function does **not** take into account decorators such as 450 | `~fabric.decorators.roles`. 451 | 452 | New in Fabric 1.3 is the `~fabric.tasks.execute` helper function, which takes a 453 | task object or name as its first argument. Using it is effectively the same as 454 | calling the given task from the command line: all the rules given above in 455 | :ref:`host-lists` apply. (The ``hosts`` and ``roles`` keyword arguments to 456 | `~fabric.tasks.execute` are analogous to :ref:`CLI per-task arguments 457 | `, including how they override all other host/role-setting 458 | methods.) 459 | 460 | As an example, here's a fabfile defining two stand-alone tasks for deploying a 461 | Web application:: 462 | 463 | from fabric.api import run, roles 464 | 465 | env.roledefs = { 466 | 'db': ['db1', 'db2'], 467 | 'web': ['web1', 'web2', 'web3'], 468 | } 469 | 470 | @roles('db') 471 | def migrate(): 472 | # Database stuff here. 473 | pass 474 | 475 | @roles('web') 476 | def update(): 477 | # Code updates here. 478 | pass 479 | 480 | In Fabric <=1.2, the only way to ensure that ``migrate`` runs on the DB servers 481 | and that ``update`` runs on the Web servers (short of manual 482 | ``env.host_string`` manipulation) was to call both as top level tasks:: 483 | 484 | $ fab migrate update 485 | 486 | Fabric >=1.3 can use `~fabric.tasks.execute` to set up a meta-task. Update the 487 | ``import`` line like so:: 488 | 489 | from fabric.api import run, roles, execute 490 | 491 | and append this to the bottom of the file:: 492 | 493 | def deploy(): 494 | execute(migrate) 495 | execute(update) 496 | 497 | That's all there is to it; the `~fabric.decorators.roles` decorators will be honored as expected, resulting in the following execution sequence: 498 | 499 | * `migrate` on `db1` 500 | * `migrate` on `db2` 501 | * `update` on `web1` 502 | * `update` on `web2` 503 | * `update` on `web3` 504 | 505 | .. warning:: 506 | This technique works because tasks that themselves have no host list (this 507 | includes the global host list settings) only run one time. If used inside a 508 | "regular" task that is going to run on multiple hosts, calls to 509 | `~fabric.tasks.execute` will also run multiple times, resulting in 510 | multiplicative numbers of subtask calls -- be careful! 511 | 512 | If you would like your `execute` calls to only be called once, you 513 | may use the `~fabric.decorators.runs_once` decorator. 514 | 515 | .. seealso:: `~fabric.tasks.execute`, `~fabric.decorators.runs_once` 516 | 517 | 518 | .. _leveraging-execute-return-value: 519 | 520 | Leveraging ``execute`` to access multi-host results 521 | --------------------------------------------------- 522 | 523 | In nontrivial Fabric runs, especially parallel ones, you may want to gather up 524 | a bunch of per-host result values at the end - e.g. to present a summary table, 525 | perform calculations, etc. 526 | 527 | It's not possible to do this in Fabric's default "naive" mode (one where you 528 | rely on Fabric looping over host lists on your behalf), but with `.execute` 529 | it's pretty easy. Simply switch from calling the actual work-bearing task, to 530 | calling a "meta" task which takes control of execution with `.execute`:: 531 | 532 | from fabric.api import task, execute, run, runs_once 533 | 534 | @task 535 | def workhorse(): 536 | return run("get my infos") 537 | 538 | @task 539 | @runs_once 540 | def go(): 541 | results = execute(workhorse) 542 | print results 543 | 544 | In the above, ``workhorse`` can do any Fabric stuff at all -- it's literally 545 | your old "naive" task -- except that it needs to return something useful. 546 | 547 | ``go`` is your new entry point (to be invoked as ``fab go``, or whatnot) and 548 | its job is to take the ``results`` dictionary from the `.execute` call and do 549 | whatever you need with it. Check the API docs for details on the structure of 550 | that return value. 551 | 552 | 553 | .. _dynamic-hosts: 554 | 555 | Using ``execute`` with dynamically-set host lists 556 | ------------------------------------------------- 557 | 558 | A common intermediate-to-advanced use case for Fabric is to parameterize lookup 559 | of one's target host list at runtime (when use of :ref:`execution-roles` does not 560 | suffice). ``execute`` can make this extremely simple, like so:: 561 | 562 | from fabric.api import run, execute, task 563 | 564 | # For example, code talking to an HTTP API, or a database, or ... 565 | from mylib import external_datastore 566 | 567 | # This is the actual algorithm involved. It does not care about host 568 | # lists at all. 569 | def do_work(): 570 | run("something interesting on a host") 571 | 572 | # This is the user-facing task invoked on the command line. 573 | @task 574 | def deploy(lookup_param): 575 | # This is the magic you don't get with @hosts or @roles. 576 | # Even lazy-loading roles require you to declare available roles 577 | # beforehand. Here, the sky is the limit. 578 | host_list = external_datastore.query(lookup_param) 579 | # Put this dynamically generated host list together with the work to be 580 | # done. 581 | execute(do_work, hosts=host_list) 582 | 583 | For example, if ``external_datastore`` was a simplistic "look up hosts by tag 584 | in a database" service, and you wanted to run a task on all hosts tagged as 585 | being related to your application stack, you might call the above like this:: 586 | 587 | $ fab deploy:app 588 | 589 | But wait! A data migration has gone awry on the DB servers. Let's fix up our 590 | migration code in our source repo, and deploy just the DB boxes again:: 591 | 592 | $ fab deploy:db 593 | 594 | This use case looks similar to Fabric's roles, but has much more potential, and 595 | is by no means limited to a single argument. Define the task however you wish, 596 | query your external data store in whatever way you need -- it's just Python. 597 | 598 | The alternate approach 599 | ~~~~~~~~~~~~~~~~~~~~~~ 600 | 601 | Similar to the above, but using ``fab``'s ability to call multiple tasks in 602 | succession instead of an explicit ``execute`` call, is to mutate 603 | :ref:`env.hosts ` in a host-list lookup task and then call ``do_work`` 604 | in the same session:: 605 | 606 | from fabric.api import run, task 607 | 608 | from mylib import external_datastore 609 | 610 | # Marked as a publicly visible task, but otherwise unchanged: still just 611 | # "do the work, let somebody else worry about what hosts to run on". 612 | @task 613 | def do_work(): 614 | run("something interesting on a host") 615 | 616 | @task 617 | def set_hosts(lookup_param): 618 | # Update env.hosts instead of calling execute() 619 | env.hosts = external_datastore.query(lookup_param) 620 | 621 | Then invoke like so:: 622 | 623 | $ fab set_hosts:app do_work 624 | 625 | One benefit of this approach over the previous one is that you can replace 626 | ``do_work`` with any other "workhorse" task:: 627 | 628 | $ fab set_hosts:db snapshot 629 | $ fab set_hosts:cassandra,cluster2 repair_ring 630 | $ fab set_hosts:redis,environ=prod status 631 | 632 | 633 | .. _failures: 634 | 635 | Failure handling 636 | ================ 637 | 638 | Once the task list has been constructed, Fabric will start executing them as 639 | outlined in :ref:`execution-strategy`, until all tasks have been run on the 640 | entirety of their host lists. However, Fabric defaults to a "fail-fast" 641 | behavior pattern: if anything goes wrong, such as a remote program returning a 642 | nonzero return value or your fabfile's Python code encountering an exception, 643 | execution will halt immediately. 644 | 645 | This is typically the desired behavior, but there are many exceptions to the 646 | rule, so Fabric provides ``env.warn_only``, a Boolean setting. It defaults to 647 | ``False``, meaning an error condition will result in the program aborting 648 | immediately. However, if ``env.warn_only`` is set to ``True`` at the time of 649 | failure -- with, say, the `~fabric.context_managers.settings` context 650 | manager -- Fabric will emit a warning message but continue executing. 651 | 652 | 653 | .. _connections: 654 | 655 | Connections 656 | =========== 657 | 658 | ``fab`` itself doesn't actually make any connections to remote hosts. Instead, 659 | it simply ensures that for each distinct run of a task on one of its hosts, the 660 | env var ``env.host_string`` is set to the right value. Users wanting to 661 | leverage Fabric as a library may do so manually to achieve similar effects 662 | (though as of Fabric 1.3, using `~fabric.tasks.execute` is preferred and more 663 | powerful.) 664 | 665 | ``env.host_string`` is (as the name implies) the "current" host string, and is 666 | what Fabric uses to determine what connections to make (or re-use) when 667 | network-aware functions are run. Operations like `~fabric.operations.run` or 668 | `~fabric.operations.put` use ``env.host_string`` as a lookup key in a shared 669 | dictionary which maps host strings to SSH connection objects. 670 | 671 | .. note:: 672 | 673 | The connections dictionary (currently located at 674 | ``fabric.state.connections``) acts as a cache, opting to return previously 675 | created connections if possible in order to save some overhead, and 676 | creating new ones otherwise. 677 | 678 | Lazy connections 679 | ---------------- 680 | 681 | Because connections are driven by the individual operations, Fabric will not 682 | actually make connections until they're necessary. Take for example this task 683 | which does some local housekeeping prior to interacting with the remote 684 | server:: 685 | 686 | from fabric.api import * 687 | 688 | @hosts('host1') 689 | def clean_and_upload(): 690 | local('find assets/ -name "*.DS_Store" -exec rm '{}' \;') 691 | local('tar czf /tmp/assets.tgz assets/') 692 | put('/tmp/assets.tgz', '/tmp/assets.tgz') 693 | with cd('/var/www/myapp/'): 694 | run('tar xzf /tmp/assets.tgz') 695 | 696 | What happens, connection-wise, is as follows: 697 | 698 | #. The two `~fabric.operations.local` calls will run without making any network 699 | connections whatsoever; 700 | #. `~fabric.operations.put` asks the connection cache for a connection to 701 | ``host1``; 702 | #. The connection cache fails to find an existing connection for that host 703 | string, and so creates a new SSH connection, returning it to 704 | `~fabric.operations.put`; 705 | #. `~fabric.operations.put` uploads the file through that connection; 706 | #. Finally, the `~fabric.operations.run` call asks the cache for a connection 707 | to that same host string, and is given the existing, cached connection for 708 | its own use. 709 | 710 | Extrapolating from this, you can also see that tasks which don't use any 711 | network-borne operations will never actually initiate any connections (though 712 | they will still be run once for each host in their host list, if any.) 713 | 714 | Closing connections 715 | ------------------- 716 | 717 | Fabric's connection cache never closes connections itself -- it leaves this up 718 | to whatever is using it. The :doc:`fab ` tool does this bookkeeping for 719 | you: it iterates over all open connections and closes them just before it exits 720 | (regardless of whether the tasks failed or not.) 721 | 722 | Library users will need to ensure they explicitly close all open connections 723 | before their program exits. This can be accomplished by calling 724 | `~fabric.network.disconnect_all` at the end of your script. 725 | 726 | .. note:: 727 | `~fabric.network.disconnect_all` may be moved to a more public location in 728 | the future; we're still working on making the library aspects of Fabric 729 | more solidified and organized. 730 | 731 | Multiple connection attempts and skipping bad hosts 732 | --------------------------------------------------- 733 | 734 | As of Fabric 1.4, multiple attempts may be made to connect to remote servers 735 | before aborting with an error: Fabric will try connecting 736 | :ref:`env.connection_attempts ` times before giving up, 737 | with a timeout of :ref:`env.timeout ` seconds each time. (These 738 | currently default to 1 try and 10 seconds, to match previous behavior, but they 739 | may be safely changed to whatever you need.) 740 | 741 | Furthermore, even total failure to connect to a server is no longer an absolute 742 | hard stop: set :ref:`env.skip_bad_hosts ` to ``True`` and in 743 | most situations (typically initial connections) Fabric will simply warn and 744 | continue, instead of aborting. 745 | 746 | .. versionadded:: 1.4 747 | 748 | .. _password-management: 749 | 750 | Password management 751 | =================== 752 | 753 | Fabric maintains an in-memory, two-tier password cache to help remember your 754 | login and sudo passwords in certain situations; this helps avoid tedious 755 | re-entry when multiple systems share the same password [#]_, or if a remote 756 | system's ``sudo`` configuration doesn't do its own caching. 757 | 758 | The first layer is a simple default or fallback password cache, 759 | :ref:`env.password ` (which may also be set at the command line via 760 | :option:`--password <-p>` or :option:`--initial-password-prompt <-I>`). This 761 | env var stores a single password which (if non-empty) will be tried in the 762 | event that the host-specific cache (see below) has no entry for the current 763 | :ref:`host string `. 764 | 765 | :ref:`env.passwords ` (plural!) serves as a per-user/per-host cache, 766 | storing the most recently entered password for every unique user/host/port 767 | combination. Due to this cache, connections to multiple different users and/or 768 | hosts in the same session will only require a single password entry for each. 769 | (Previous versions of Fabric used only the single, default password cache and 770 | thus required password re-entry every time the previously entered password 771 | became invalid.) 772 | 773 | Depending on your configuration and the number of hosts your session will 774 | connect to, you may find setting either or both of these env vars to be useful. 775 | However, Fabric will automatically fill them in as necessary without any 776 | additional configuration. 777 | 778 | Specifically, each time a password prompt is presented to the user, the value 779 | entered is used to update both the single default password cache, and the cache 780 | value for the current value of ``env.host_string``. 781 | 782 | .. [#] We highly recommend the use of SSH `key-based access 783 | `_ instead of relying on 784 | homogeneous password setups, as it's significantly more secure. 785 | 786 | 787 | .. _ssh-config: 788 | 789 | Leveraging native SSH config files 790 | ================================== 791 | 792 | Command-line SSH clients (such as the one provided by `OpenSSH 793 | `_) make use of a specific configuration format typically 794 | known as ``ssh_config``, and will read from a file in the platform-specific 795 | location ``$HOME/.ssh/config`` (or an arbitrary path given to 796 | :option:`--ssh-config-path`/:ref:`env.ssh_config_path `.) This 797 | file allows specification of various SSH options such as default or per-host 798 | usernames, hostname aliases, and toggling other settings (such as whether to 799 | use :ref:`agent forwarding `.) 800 | 801 | Fabric's SSH implementation allows loading a subset of these options from one's 802 | actual SSH config file, should it exist. This behavior is not enabled by 803 | default (in order to be backwards compatible) but may be turned on by setting 804 | :ref:`env.use_ssh_config ` to ``True`` at the top of your 805 | fabfile. 806 | 807 | If enabled, the following SSH config directives will be loaded and honored by Fabric: 808 | 809 | * ``User`` and ``Port`` will be used to fill in the appropriate connection 810 | parameters when not otherwise specified, in the following fashion: 811 | 812 | * Globally specified ``User``/``Port`` will be used in place of the current 813 | defaults (local username and 22, respectively) if the appropriate env vars 814 | are not set. 815 | * However, if :ref:`env.user `/:ref:`env.port ` *are* set, they 816 | override global ``User``/``Port`` values. 817 | * User/port values in the host string itself (e.g. ``hostname:222``) will 818 | override everything, including any ``ssh_config`` values. 819 | * ``HostName`` can be used to replace the given hostname, just like with 820 | regular ``ssh``. So a ``Host foo`` entry specifying ``HostName example.com`` 821 | will allow you to give Fabric the hostname ``'foo'`` and have that expanded 822 | into ``'example.com'`` at connection time. 823 | * ``IdentityFile`` will extend (not replace) :ref:`env.key_filename 824 | `. 825 | * ``ForwardAgent`` will augment :ref:`env.forward_agent ` in an 826 | "OR" manner: if either is set to a positive value, agent forwarding will be 827 | enabled. 828 | * ``ProxyCommand`` will trigger use of a proxy command for host connections, 829 | just as with regular ``ssh``. 830 | 831 | .. note:: 832 | If all you want to do is bounce SSH traffic off a gateway, you may find 833 | :ref:`env.gateway ` to be a more efficient connection method 834 | (which will also honor more Fabric-level settings) than the typical ``ssh 835 | gatewayhost nc %h %p`` method of using ``ProxyCommand`` as a gateway. 836 | 837 | .. note:: 838 | If your SSH config file contains ``ProxyCommand`` directives *and* you have 839 | set :ref:`env.gateway ` to a non-``None`` value, ``env.gateway`` 840 | will take precedence and the ``ProxyCommand`` will be ignored. 841 | 842 | If one has a pre-created SSH config file, rationale states it will be 843 | easier for you to modify ``env.gateway`` (e.g. via 844 | `~fabric.context_managers.settings`) than to work around your conf file's 845 | contents entirely. 846 | -------------------------------------------------------------------------------- /usage/fab.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | ``fab`` options and arguments 3 | ============================= 4 | 5 | The most common method for utilizing Fabric is via its command-line tool, 6 | ``fab``, which should have been placed on your shell's executable path when 7 | Fabric was installed. ``fab`` tries hard to be a good Unix citizen, using a 8 | standard style of command-line switches, help output, and so forth. 9 | 10 | 11 | Basic use 12 | ========= 13 | 14 | In its most simple form, ``fab`` may be called with no options at all, and 15 | with one or more arguments, which should be task names, e.g.:: 16 | 17 | $ fab task1 task2 18 | 19 | As detailed in :doc:`../tutorial` and :doc:`execution`, this will run ``task1`` 20 | followed by ``task2``, assuming that Fabric was able to find a fabfile nearby 21 | containing Python functions with those names. 22 | 23 | However, it's possible to expand this simple usage into something more 24 | flexible, by using the provided options and/or passing arguments to individual 25 | tasks. 26 | 27 | 28 | .. _arbitrary-commands: 29 | 30 | Arbitrary remote shell commands 31 | =============================== 32 | 33 | .. versionadded:: 0.9.2 34 | 35 | Fabric leverages a lesser-known command line convention and may be called in 36 | the following manner:: 37 | 38 | $ fab [options] -- [shell command] 39 | 40 | where everything after the ``--`` is turned into a temporary 41 | `~fabric.operations.run` call, and is not parsed for ``fab`` options. If you've 42 | defined a host list at the module level or on the command line, this usage will 43 | act like a one-line anonymous task. 44 | 45 | For example, let's say you just wanted to get the kernel info for a bunch of 46 | systems; you could do this:: 47 | 48 | $ fab -H system1,system2,system3 -- uname -a 49 | 50 | which would be literally equivalent to the following fabfile:: 51 | 52 | from fabric.api import run 53 | 54 | def anonymous(): 55 | run("uname -a") 56 | 57 | as if it were executed thusly:: 58 | 59 | $ fab -H system1,system2,system3 anonymous 60 | 61 | Most of the time you will want to just write out the task in your fabfile 62 | (anything you use once, you're likely to use again) but this feature provides a 63 | handy, fast way to quickly dash off an SSH-borne command while leveraging your 64 | fabfile's connection settings. 65 | 66 | 67 | .. _command-line-options: 68 | 69 | Command-line options 70 | ==================== 71 | 72 | A quick overview of all possible command line options can be found via ``fab 73 | --help``. If you're looking for details on a specific option, we go into detail 74 | below. 75 | 76 | .. note:: 77 | 78 | ``fab`` uses Python's `optparse`_ library, meaning that it honors typical 79 | Linux or GNU style short and long options, as well as freely mixing options 80 | and arguments. E.g. ``fab task1 -H hostname task2 -i path/to/keyfile`` is 81 | just as valid as the more straightforward ``fab -H hostname -i 82 | path/to/keyfile task1 task2``. 83 | 84 | .. _optparse: http://docs.python.org/library/optparse.html 85 | 86 | .. cmdoption:: -a, --no_agent 87 | 88 | Sets :ref:`env.no_agent ` to ``True``, forcing our SSH layer not 89 | to talk to the SSH agent when trying to unlock private key files. 90 | 91 | .. versionadded:: 0.9.1 92 | 93 | .. cmdoption:: -A, --forward-agent 94 | 95 | Sets :ref:`env.forward_agent ` to ``True``, enabling agent 96 | forwarding. 97 | 98 | .. versionadded:: 1.4 99 | 100 | .. cmdoption:: --abort-on-prompts 101 | 102 | Sets :ref:`env.abort_on_prompts ` to ``True``, forcing 103 | Fabric to abort whenever it would prompt for input. 104 | 105 | .. versionadded:: 1.1 106 | 107 | .. cmdoption:: -c RCFILE, --config=RCFILE 108 | 109 | Sets :ref:`env.rcfile ` to the given file path, which Fabric will 110 | try to load on startup and use to update environment variables. 111 | 112 | .. cmdoption:: -d COMMAND, --display=COMMAND 113 | 114 | Prints the entire docstring for the given task, if there is one. Does not 115 | currently print out the task's function signature, so descriptive 116 | docstrings are a good idea. (They're *always* a good idea, of course -- 117 | just moreso here.) 118 | 119 | .. cmdoption:: --connection-attempts=M, -n M 120 | 121 | Set number of times to attempt connections. Sets 122 | :ref:`env.connection_attempts `. 123 | 124 | .. seealso:: 125 | :ref:`env.connection_attempts `, 126 | :ref:`env.timeout ` 127 | .. versionadded:: 1.4 128 | 129 | .. cmdoption:: -D, --disable-known-hosts 130 | 131 | Sets :ref:`env.disable_known_hosts ` to ``True``, 132 | preventing Fabric from loading the user's SSH :file:`known_hosts` file. 133 | 134 | .. cmdoption:: -f FABFILE, --fabfile=FABFILE 135 | 136 | The fabfile name pattern to search for (defaults to ``fabfile.py``), or 137 | alternately an explicit file path to load as the fabfile (e.g. 138 | ``/path/to/my/fabfile.py``.) 139 | 140 | .. seealso:: :doc:`fabfiles` 141 | 142 | .. cmdoption:: -F LIST_FORMAT, --list-format=LIST_FORMAT 143 | 144 | Allows control over the output format of :option:`--list <-l>`. ``short`` is 145 | equivalent to :option:`--shortlist`, ``normal`` is the same as simply 146 | omitting this option entirely (i.e. the default), and ``nested`` prints out 147 | a nested namespace tree. 148 | 149 | .. versionadded:: 1.1 150 | .. seealso:: :option:`--shortlist`, :option:`--list <-l>` 151 | 152 | .. cmdoption:: -g HOST, --gateway=HOST 153 | 154 | Sets :ref:`env.gateway ` to ``HOST`` host string. 155 | 156 | .. versionadded:: 1.5 157 | 158 | .. cmdoption:: -h, --help 159 | 160 | Displays a standard help message, with all possible options and a brief 161 | overview of what they do, then exits. 162 | 163 | .. cmdoption:: --hide=LEVELS 164 | 165 | A comma-separated list of :doc:`output levels ` to hide by 166 | default. 167 | 168 | 169 | .. cmdoption:: -H HOSTS, --hosts=HOSTS 170 | 171 | Sets :ref:`env.hosts ` to the given comma-delimited list of host 172 | strings. 173 | 174 | .. cmdoption:: -x HOSTS, --exclude-hosts=HOSTS 175 | 176 | Sets :ref:`env.exclude_hosts ` to the given comma-delimited 177 | list of host strings to then keep out of the final host list. 178 | 179 | .. versionadded:: 1.1 180 | 181 | .. cmdoption:: -i KEY_FILENAME 182 | 183 | When set to a file path, will load the given file as an SSH identity file 184 | (usually a private key.) This option may be repeated multiple times. Sets 185 | (or appends to) :ref:`env.key_filename `. 186 | 187 | .. cmdoption:: -I, --initial-password-prompt 188 | 189 | Forces a password prompt at the start of the session (after fabfile load 190 | and option parsing, but before executing any tasks) in order to pre-fill 191 | :ref:`env.password `. 192 | 193 | This is useful for fire-and-forget runs (especially parallel sessions, in 194 | which runtime input is not possible) when setting the password via 195 | :option:`--password <-p>` or by setting :ref:`env.password ` in 196 | your fabfile, is undesirable. 197 | 198 | .. note:: The value entered into this prompt will *overwrite* anything 199 | supplied via :ref:`env.password ` at module level, or via 200 | :option:`--password <-p>`. 201 | 202 | .. seealso:: :ref:`password-management` 203 | 204 | .. cmdoption:: -k 205 | 206 | Sets :ref:`env.no_keys ` to ``True``, forcing the SSH layer to not 207 | look for SSH private key files in one's home directory. 208 | 209 | .. versionadded:: 0.9.1 210 | 211 | .. cmdoption:: --keepalive=KEEPALIVE 212 | 213 | Sets :ref:`env.keepalive ` to the given (integer) value, specifying an SSH keepalive interval. 214 | 215 | .. versionadded:: 1.1 216 | 217 | .. cmdoption:: --linewise 218 | 219 | Forces output to be buffered line-by-line instead of byte-by-byte. Often useful or required for :ref:`parallel execution `. 220 | 221 | .. versionadded:: 1.3 222 | 223 | .. cmdoption:: -l, --list 224 | 225 | Imports a fabfile as normal, but then prints a list of all discovered tasks 226 | and exits. Will also print the first line of each task's docstring, if it 227 | has one, next to it (truncating if necessary.) 228 | 229 | .. versionchanged:: 0.9.1 230 | Added docstring to output. 231 | .. seealso:: :option:`--shortlist`, :option:`--list-format <-F>` 232 | 233 | .. cmdoption:: -p PASSWORD, --password=PASSWORD 234 | 235 | Sets :ref:`env.password ` to the given string; it will then be 236 | used as the default password when making SSH connections or calling the 237 | ``sudo`` program. 238 | 239 | .. seealso:: :option:`--initial-password-prompt <-I>` 240 | 241 | .. cmdoption:: -P, --parallel 242 | 243 | Sets :ref:`env.parallel ` to ``True``, causing 244 | tasks to run in parallel. 245 | 246 | .. versionadded:: 1.3 247 | .. seealso:: :doc:`/usage/parallel` 248 | 249 | .. cmdoption:: --no-pty 250 | 251 | Sets :ref:`env.always_use_pty ` to ``False``, causing all 252 | `~fabric.operations.run`/`~fabric.operations.sudo` calls to behave as if 253 | one had specified ``pty=False``. 254 | 255 | .. versionadded:: 1.0 256 | 257 | .. cmdoption:: -r, --reject-unknown-hosts 258 | 259 | Sets :ref:`env.reject_unknown_hosts ` to ``True``, 260 | causing Fabric to abort when connecting to hosts not found in the user's SSH 261 | :file:`known_hosts` file. 262 | 263 | .. cmdoption:: -R ROLES, --roles=ROLES 264 | 265 | Sets :ref:`env.roles ` to the given comma-separated list of role 266 | names. 267 | 268 | .. cmdoption:: --set KEY=VALUE,... 269 | 270 | Allows you to set default values for arbitrary Fabric env vars. Values set 271 | this way have a low precedence -- they will not override more specific env 272 | vars which are also specified on the command line. E.g.:: 273 | 274 | fab --set password=foo --password=bar 275 | 276 | will result in ``env.password = 'bar'``, not ``'foo'`` 277 | 278 | Multiple ``KEY=VALUE`` pairs may be comma-separated, e.g. ``fab --set 279 | var1=val1,var2=val2``. 280 | 281 | Other than basic string values, you may also set env vars to True by 282 | omitting the ``=VALUE`` (e.g. ``fab --set KEY``), and you may set values to 283 | the empty string (and thus a False-equivalent value) by keeping the equals 284 | sign, but omitting ``VALUE`` (e.g. ``fab --set KEY=``.) 285 | 286 | .. versionadded:: 1.4 287 | 288 | .. cmdoption:: -s SHELL, --shell=SHELL 289 | 290 | Sets :ref:`env.shell ` to the given string, overriding the default 291 | shell wrapper used to execute remote commands. 292 | 293 | .. cmdoption:: --shortlist 294 | 295 | Similar to :option:`--list <-l>`, but without any embellishment, just task 296 | names separated by newlines with no indentation or docstrings. 297 | 298 | .. versionadded:: 0.9.2 299 | .. seealso:: :option:`--list <-l>` 300 | 301 | .. cmdoption:: --show=LEVELS 302 | 303 | A comma-separated list of :doc:`output levels ` to 304 | be added to those that are shown by 305 | default. 306 | 307 | .. seealso:: `~fabric.operations.run`, `~fabric.operations.sudo` 308 | 309 | .. cmdoption:: --ssh-config-path 310 | 311 | Sets :ref:`env.ssh_config_path `. 312 | 313 | .. versionadded:: 1.4 314 | .. seealso:: :ref:`ssh-config` 315 | 316 | .. cmdoption:: --skip-bad-hosts 317 | 318 | Sets :ref:`env.skip_bad_hosts `, causing Fabric to skip 319 | unavailable hosts. 320 | 321 | .. versionadded:: 1.4 322 | 323 | .. cmdoption:: --timeout=N, -t N 324 | 325 | Set connection timeout in seconds. Sets :ref:`env.timeout `. 326 | 327 | .. seealso:: 328 | :ref:`env.timeout `, 329 | :ref:`env.connection_attempts ` 330 | .. versionadded:: 1.4 331 | 332 | .. cmdoption:: --command-timeout=N, -T N 333 | 334 | Set remote command timeout in seconds. Sets 335 | :ref:`env.command_timeout `. 336 | 337 | .. seealso:: 338 | :ref:`env.command_timeout `, 339 | 340 | .. versionadded:: 1.6 341 | 342 | .. cmdoption:: -u USER, --user=USER 343 | 344 | Sets :ref:`env.user ` to the given string; it will then be used as the 345 | default username when making SSH connections. 346 | 347 | .. cmdoption:: -V, --version 348 | 349 | Displays Fabric's version number, then exits. 350 | 351 | .. cmdoption:: -w, --warn-only 352 | 353 | Sets :ref:`env.warn_only ` to ``True``, causing Fabric to 354 | continue execution even when commands encounter error conditions. 355 | 356 | .. cmdoption:: -z, --pool-size 357 | 358 | Sets :ref:`env.pool_size `, which specifies how many processes 359 | to run concurrently during parallel execution. 360 | 361 | .. versionadded:: 1.3 362 | .. seealso:: :doc:`/usage/parallel` 363 | 364 | 365 | .. _task-arguments: 366 | 367 | Per-task arguments 368 | ================== 369 | 370 | The options given in :ref:`command-line-options` apply to the invocation of 371 | ``fab`` as a whole; even if the order is mixed around, options still apply to 372 | all given tasks equally. Additionally, since tasks are just Python functions, 373 | it's often desirable to pass in arguments to them at runtime. 374 | 375 | Answering both these needs is the concept of "per-task arguments", which is a 376 | special syntax you can tack onto the end of any task name: 377 | 378 | * Use a colon (``:``) to separate the task name from its arguments; 379 | * Use commas (``,``) to separate arguments from one another (may be escaped 380 | by using a backslash, i.e. ``\,``); 381 | * Use equals signs (``=``) for keyword arguments, or omit them for positional 382 | arguments. May also be escaped with backslashes. 383 | 384 | Additionally, since this process involves string parsing, all values will end 385 | up as Python strings, so plan accordingly. (We hope to improve upon this in 386 | future versions of Fabric, provided an intuitive syntax can be found.) 387 | 388 | For example, a "create a new user" task might be defined like so (omitting most 389 | of the actual logic for brevity):: 390 | 391 | def new_user(username, admin='no', comment="No comment provided"): 392 | print("New User (%s): %s" % (username, comment)) 393 | pass 394 | 395 | You can specify just the username:: 396 | 397 | $ fab new_user:myusername 398 | 399 | Or treat it as an explicit keyword argument:: 400 | 401 | $ fab new_user:username=myusername 402 | 403 | If both args are given, you can again give them as positional args:: 404 | 405 | $ fab new_user:myusername,yes 406 | 407 | Or mix and match, just like in Python:: 408 | 409 | $ fab new_user:myusername,admin=yes 410 | 411 | The ``print`` call above is useful for illustrating escaped commas, like 412 | so:: 413 | 414 | $ fab new_user:myusername,admin=no,comment='Gary\, new developer (starts Monday)' 415 | 416 | .. note:: 417 | Quoting the backslash-escaped comma is required, as not doing so will cause 418 | shell syntax errors. Quotes are also needed whenever an argument involves 419 | other shell-related characters such as spaces. 420 | 421 | All of the above are translated into the expected Python function calls. For 422 | example, the last call above would become:: 423 | 424 | >>> new_user('myusername', admin='yes', comment='Gary, new developer (starts Monday)') 425 | 426 | Roles and hosts 427 | --------------- 428 | 429 | As mentioned in :ref:`the section on task execution `, 430 | there are a handful of per-task keyword arguments (``host``, ``hosts``, 431 | ``role`` and ``roles``) which do not actually map to the task functions 432 | themselves, but are used for setting per-task host and/or role lists. 433 | 434 | These special kwargs are **removed** from the args/kwargs sent to the task 435 | function itself; this is so that you don't run into TypeErrors if your task 436 | doesn't define the kwargs in question. (It also means that if you **do** define 437 | arguments with these names, you won't be able to specify them in this manner -- 438 | a regrettable but necessary sacrifice.) 439 | 440 | .. note:: 441 | 442 | If both the plural and singular forms of these kwargs are given, the value 443 | of the plural will win out and the singular will be discarded. 444 | 445 | When using the plural form of these arguments, one must use semicolons (``;``) 446 | since commas are already being used to separate arguments from one another. 447 | Furthermore, since your shell is likely to consider semicolons a special 448 | character, you'll want to quote the host list string to prevent shell 449 | interpretation, e.g.:: 450 | 451 | $ fab new_user:myusername,hosts="host1;host2" 452 | 453 | Again, since the ``hosts`` kwarg is removed from the argument list sent to the 454 | ``new_user`` task function, the actual Python invocation would be 455 | ``new_user('myusername')``, and the function would be executed on a host list 456 | of ``['host1', 'host2']``. 457 | 458 | .. _fabricrc: 459 | 460 | Settings files 461 | ============== 462 | 463 | Fabric currently honors a simple user settings file, or ``fabricrc`` (think 464 | ``bashrc`` but for ``fab``) which should contain one or more key-value pairs, 465 | one per line. These lines will be subject to ``string.split('=')``, and thus 466 | can currently only be used to specify string settings. Any such key-value pairs 467 | will be used to update :doc:`env ` when ``fab`` runs, and is loaded prior 468 | to the loading of any fabfile. 469 | 470 | By default, Fabric looks for ``~/.fabricrc``, and this may be overridden by 471 | specifying the :option:`-c` flag to ``fab``. 472 | 473 | For example, if your typical SSH login username differs from your workstation 474 | username, and you don't want to modify ``env.user`` in a project's fabfile 475 | (possibly because you expect others to use it as well) you could write a 476 | ``fabricrc`` file like so:: 477 | 478 | user = ssh_user_name 479 | 480 | Then, when running ``fab``, your fabfile would load up with ``env.user`` set to 481 | ``'ssh_user_name'``. Other users of that fabfile could do the same, allowing 482 | the fabfile itself to be cleanly agnostic regarding the default username. 483 | -------------------------------------------------------------------------------- /usage/fabfiles.rst: -------------------------------------------------------------------------------- 1 | ============================ 2 | Fabfile construction and use 3 | ============================ 4 | 5 | This document contains miscellaneous sections about fabfiles, both how to best 6 | write them, and how to use them once written. 7 | 8 | .. _fabfile-discovery: 9 | 10 | Fabfile discovery 11 | ================= 12 | 13 | Fabric is capable of loading Python modules (e.g. ``fabfile.py``) or packages 14 | (e.g. a ``fabfile/`` directory containing an ``__init__.py``). By default, it 15 | looks for something named (to Python's import machinery) ``fabfile`` - so 16 | either ``fabfile/`` or ``fabfile.py``. 17 | 18 | The fabfile discovery algorithm searches in the invoking user's current working 19 | directory or any parent directories. Thus, it is oriented around "project" use, 20 | where one keeps e.g. a ``fabfile.py`` at the root of a source code tree. Such a 21 | fabfile will then be discovered no matter where in the tree the user invokes 22 | ``fab``. 23 | 24 | The specific name to be searched for may be overridden on the command-line with 25 | the :option:`-f` option, or by adding a :ref:`fabricrc ` line which 26 | sets the value of ``fabfile``. For example, if you wanted to name your fabfile 27 | ``fab_tasks.py``, you could create such a file and then call ``fab -f 28 | fab_tasks.py ``, or add ``fabfile = fab_tasks.py`` to 29 | ``~/.fabricrc``. 30 | 31 | If the given fabfile name contains path elements other than a filename (e.g. 32 | ``../fabfile.py`` or ``/dir1/dir2/custom_fabfile``) it will be treated as a 33 | file path and directly checked for existence without any sort of searching. 34 | When in this mode, tilde-expansion will be applied, so one may refer to e.g. 35 | ``~/personal_fabfile.py``. 36 | 37 | .. note:: 38 | 39 | Fabric does a normal ``import`` (actually an ``__import__``) of your 40 | fabfile in order to access its contents -- it does not do any ``eval``-ing 41 | or similar. In order for this to work, Fabric temporarily adds the found 42 | fabfile's containing folder to the Python load path (and removes it 43 | immediately afterwards.) 44 | 45 | .. versionchanged:: 0.9.2 46 | The ability to load package fabfiles. 47 | 48 | 49 | .. _importing-the-api: 50 | 51 | Importing Fabric 52 | ================ 53 | 54 | Because Fabric is just Python, you *can* import its components any way you 55 | want. However, for the purposes of encapsulation and convenience (and to make 56 | life easier for Fabric's packaging script) Fabric's public API is maintained in 57 | the ``fabric.api`` module. 58 | 59 | All of Fabric's :doc:`../api/core/operations`, 60 | :doc:`../api/core/context_managers`, :doc:`../api/core/decorators` and 61 | :doc:`../api/core/utils` are included in this module as a single, flat 62 | namespace. This enables a very simple and consistent interface to Fabric within 63 | your fabfiles:: 64 | 65 | from fabric.api import * 66 | 67 | # call run(), sudo(), etc etc 68 | 69 | This is not technically best practices (for `a 70 | number of reasons`_) and if you're only using a couple of 71 | Fab API calls, it *is* probably a good idea to explicitly ``from fabric.api 72 | import env, run`` or similar. However, in most nontrivial fabfiles, you'll be 73 | using all or most of the API, and the star import:: 74 | 75 | from fabric.api import * 76 | 77 | will be a lot easier to write and read than:: 78 | 79 | from fabric.api import abort, cd, env, get, hide, hosts, local, prompt, \ 80 | put, require, roles, run, runs_once, settings, show, sudo, warn 81 | 82 | so in this case we feel pragmatism overrides best practices. 83 | 84 | .. _a number of reasons: http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#importing 85 | 86 | 87 | Defining tasks and importing callables 88 | ====================================== 89 | 90 | For important information on what exactly Fabric will consider as a task when 91 | it loads your fabfile, as well as notes on how best to import other code, 92 | please see :doc:`/usage/tasks` in the :doc:`execution` documentation. 93 | -------------------------------------------------------------------------------- /usage/interactivity.rst: -------------------------------------------------------------------------------- 1 | ================================ 2 | Interaction with remote programs 3 | ================================ 4 | 5 | Fabric's primary operations, `~fabric.operations.run` and 6 | `~fabric.operations.sudo`, are capable of sending local input to the remote 7 | end, in a manner nearly identical to the ``ssh`` program. For example, programs 8 | which display password prompts (e.g. a database dump utility, or changing a 9 | user's password) will behave just as if you were interacting with them 10 | directly. 11 | 12 | However, as with ``ssh`` itself, Fabric's implementation of this feature is 13 | subject to a handful of limitations which are not always intuitive. This 14 | document discusses such issues in detail. 15 | 16 | .. note:: 17 | Readers unfamiliar with the basics of Unix stdout and stderr pipes, and/or 18 | terminal devices, may wish to visit the Wikipedia pages for `Unix pipelines 19 | `_ and `Pseudo terminals 20 | `_ respectively. 21 | 22 | 23 | .. _combine_streams: 24 | 25 | Combining stdout and stderr 26 | =========================== 27 | 28 | The first issue to be aware of is that of the stdout and stderr streams, and 29 | why they are separated or combined as needed. 30 | 31 | Buffering 32 | --------- 33 | 34 | Fabric 0.9.x and earlier, and Python itself, buffer output on a line-by-line 35 | basis: text is not printed to the user until a newline character is found. 36 | This works fine in most situations but becomes problematic when one needs to 37 | deal with partial-line output such as prompts. 38 | 39 | .. note:: 40 | Line-buffered output can make programs appear to halt or freeze for no 41 | reason, as prompts print out text without a newline, waiting for the user 42 | to enter their input and press Return. 43 | 44 | Newer Fabric versions buffer both input and output on a character-by-character 45 | basis in order to make interaction with prompts possible. This has the 46 | convenient side effect of enabling interaction with complex programs utilizing 47 | the "curses" libraries or which otherwise redraw the screen (think ``top``). 48 | 49 | Crossing the streams 50 | -------------------- 51 | 52 | Unfortunately, printing to stderr and stdout simultaneously (as many programs 53 | do) means that when the two streams are printed independently one byte at a 54 | time, they can become garbled or meshed together. While this can sometimes be 55 | mitigated by line-buffering one of the streams and not the other, it's still a 56 | serious issue. 57 | 58 | To solve this problem, Fabric uses a setting in our SSH layer which merges the 59 | two streams at a low level and causes output to appear more naturally. This 60 | setting is represented in Fabric as the :ref:`combine-stderr` env var and 61 | keyword argument, and is ``True`` by default. 62 | 63 | Due to this default setting, output will appear correctly, but at the 64 | cost of an empty ``.stderr`` attribute on the return values of 65 | `~fabric.operations.run`/`~fabric.operations.sudo`, as all output will appear 66 | to be stdout. 67 | 68 | Conversely, users requiring a distinct stderr stream at the Python level and 69 | who aren't bothered by garbled user-facing output (or who are hiding stdout and 70 | stderr from the command in question) may opt to set this to ``False`` as 71 | needed. 72 | 73 | 74 | .. _pseudottys: 75 | 76 | Pseudo-terminals 77 | ================ 78 | 79 | The other main issue to consider when presenting interactive prompts to users 80 | is that of echoing the user's own input. 81 | 82 | Echoes 83 | ------ 84 | 85 | Typical terminal applications or bona fide text terminals (e.g. when using a 86 | Unix system without a running GUI) present programs with a terminal device 87 | called a tty or pty (for pseudo-terminal). These automatically echo all text 88 | typed into them back out to the user (via stdout), as interaction without 89 | seeing what you had just typed would be difficult. Terminal devices are also 90 | able to conditionally turn off echoing, allowing secure password prompts. 91 | 92 | However, it's possible for programs to be run without a tty or pty present at 93 | all (consider cron jobs, for example) and in this situation, any stdin data 94 | being fed to the program won't be echoed. This is desirable for programs being 95 | run without any humans around, and it's also Fabric's old default mode of 96 | operation. 97 | 98 | Fabric's approach 99 | ----------------- 100 | 101 | Unfortunately, in the context of executing commands via Fabric, when no pty is 102 | present to echo a user's stdin, Fabric must echo it for them. This is 103 | sufficient for many applications, but it presents problems for password 104 | prompts, which become insecure. 105 | 106 | In the interests of security and meeting the principle of least surprise 107 | (insofar as users are typically expecting things to behave as they would when 108 | run in a terminal emulator), Fabric 1.0 and greater force a pty by default. 109 | With a pty enabled, Fabric simply allows the remote end to handle echoing or 110 | hiding of stdin and does not echo anything itself. 111 | 112 | .. note:: 113 | In addition to allowing normal echo behavior, a pty also means programs 114 | that behave differently when attached to a terminal device will then do so. 115 | For example, programs that colorize output on terminals but not when run in 116 | the background will print colored output. Be wary of this if you inspect 117 | the return value of `~fabric.operations.run` or `~fabric.operations.sudo`! 118 | 119 | For situations requiring the pty behavior turned off, the :option:`--no-pty` 120 | command-line argument and :ref:`always-use-pty` env var may be used. 121 | 122 | 123 | Combining the two 124 | ================= 125 | 126 | As a final note, keep in mind that use of pseudo-terminals effectively implies 127 | combining stdout and stderr -- in much the same way as the :ref:`combine_stderr 128 | ` setting does. This is because a terminal device naturally 129 | sends both stdout and stderr to the same place -- the user's display -- thus 130 | making it impossible to differentiate between them. 131 | 132 | However, at the Fabric level, the two groups of settings are distinct from one 133 | another and may be combined in various ways. The default is for both to be set 134 | to ``True``; the other combinations are as follows: 135 | 136 | * ``run("cmd", pty=False, combine_stderr=True)``: will cause Fabric to echo all 137 | stdin itself, including passwords, as well as potentially altering ``cmd``'s 138 | behavior. Useful if ``cmd`` behaves undesirably when run under a pty and 139 | you're not concerned about password prompts. 140 | * ``run("cmd", pty=False, combine_stderr=False)``: with both settings 141 | ``False``, Fabric will echo stdin and won't issue a pty -- and this is highly 142 | likely to result in undesired behavior for all but the simplest commands. 143 | However, it is also the only way to access a distinct stderr stream, which is 144 | occasionally useful. 145 | * ``run("cmd", pty=True, combine_stderr=False)``: valid, but won't really make 146 | much of a difference, as ``pty=True`` will still result in merged streams. 147 | May be useful for avoiding any edge case problems in ``combine_stderr`` (none 148 | are presently known). 149 | -------------------------------------------------------------------------------- /usage/library.rst: -------------------------------------------------------------------------------- 1 | =========== 2 | Library Use 3 | =========== 4 | 5 | Fabric's primary use case is via fabfiles and the :doc:`fab ` tool, 6 | and this is reflected in much of the documentation. However, Fabric's internals 7 | are written in such a manner as to be easily used without ``fab`` or fabfiles 8 | at all -- this document will show you how. 9 | 10 | There's really only a couple of considerations one must keep in mind, when 11 | compared to writing a fabfile and using ``fab`` to run it: how connections are 12 | really made, and how disconnections occur. 13 | 14 | Connections 15 | =========== 16 | 17 | We've documented how Fabric really connects to its hosts before, but it's 18 | currently somewhat buried in the middle of the overall :doc:`execution docs 19 | `. Specifically, you'll want to skip over to the 20 | :ref:`connections` section and read it real quick. (You should really give that 21 | entire document a once-over, but it's not absolutely required.) 22 | 23 | As that section mentions, the key is simply that `~fabric.operations.run`, 24 | `~fabric.operations.sudo` and the other operations only look in one place when 25 | connecting: :ref:`env.host_string `. All of the other mechanisms 26 | for setting hosts are interpreted by the ``fab`` tool when it runs, and don't 27 | matter when running as a library. 28 | 29 | That said, most use cases where you want to marry a given task ``X`` and a given list of hosts ``Y`` can, as of Fabric 1.3, be handled with the `~fabric.tasks.execute` function via ``execute(X, hosts=Y)``. Please see `~fabric.tasks.execute`'s documentation for details -- manual host string manipulation should be rarely necessary. 30 | 31 | Disconnecting 32 | ============= 33 | 34 | The other main thing that ``fab`` does for you is to disconnect from all hosts 35 | at the end of a session; otherwise, Python will sit around forever waiting for 36 | those network resources to be released. 37 | 38 | Fabric 0.9.4 and newer have a function you can use to do this easily: 39 | `~fabric.network.disconnect_all`. Simply make sure your code calls this when it 40 | terminates (typically in the ``finally`` clause of an outer ``try: finally`` 41 | statement -- lest errors in your code prevent disconnections from happening!) 42 | and things ought to work pretty well. 43 | 44 | If you're on Fabric 0.9.3 or older, you can simply do this (``disconnect_all`` 45 | just adds a bit of nice output to this logic):: 46 | 47 | from fabric.state import connections 48 | 49 | for key in connections.keys(): 50 | connections[key].close() 51 | del connections[key] 52 | 53 | 54 | Final note 55 | ========== 56 | 57 | This document is an early draft, and may not cover absolutely every difference 58 | between ``fab`` use and library use. However, the above should highlight the 59 | largest stumbling blocks. When in doubt, note that in the Fabric source code, 60 | ``fabric/main.py`` contains the bulk of the extra work done by ``fab``, and may 61 | serve as a useful reference. 62 | -------------------------------------------------------------------------------- /usage/output_controls.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Managing output 3 | =============== 4 | 5 | The ``fab`` tool is very verbose by default and prints out almost everything it 6 | can, including the remote end's stderr and stdout streams, the command strings 7 | being executed, and so forth. While this is necessary in many cases in order to 8 | know just what's going on, any nontrivial Fabric task will quickly become 9 | difficult to follow as it runs. 10 | 11 | 12 | Output levels 13 | ============= 14 | 15 | To aid in organizing task output, Fabric output is grouped into a number of 16 | non-overlapping levels or groups, each of which may be turned on or off 17 | independently. This provides flexible control over what is displayed to the 18 | user. 19 | 20 | .. note:: 21 | 22 | All levels, save for ``debug``, are on by default. 23 | 24 | Standard output levels 25 | ---------------------- 26 | 27 | The standard, atomic output levels/groups are as follows: 28 | 29 | * **status**: Status messages, i.e. noting when Fabric is done running, if 30 | the user used a keyboard interrupt, or when servers are disconnected from. 31 | These messages are almost always relevant and rarely verbose. 32 | 33 | * **aborts**: Abort messages. Like status messages, these should really only be 34 | turned off when using Fabric as a library, and possibly not even then. Note 35 | that even if this output group is turned off, aborts will still occur -- 36 | there just won't be any output about why Fabric aborted! 37 | 38 | * **warnings**: Warning messages. These are often turned off when one expects a 39 | given operation to fail, such as when using ``grep`` to test existence of 40 | text in a file. If paired with setting ``env.warn_only`` to True, this 41 | can result in fully silent warnings when remote programs fail. As with 42 | ``aborts``, this setting does not control actual warning behavior, only 43 | whether warning messages are printed or hidden. 44 | 45 | * **running**: Printouts of commands being executed or files transferred, e.g. 46 | ``[myserver] run: ls /var/www``. Also controls printing of tasks being run, 47 | e.g. ``[myserver] Executing task 'foo'``. 48 | 49 | * **stdout**: Local, or remote, stdout, i.e. non-error output from commands. 50 | 51 | * **stderr**: Local, or remote, stderr, i.e. error-related output from commands. 52 | 53 | * **user**: User-generated output, i.e. local output printed by fabfile code 54 | via use of the `~fabric.utils.fastprint` or `~fabric.utils.puts` functions. 55 | 56 | .. versionchanged:: 0.9.2 57 | Added "Executing task" lines to the ``running`` output level. 58 | 59 | .. versionchanged:: 0.9.2 60 | Added the ``user`` output level. 61 | 62 | Debug output 63 | ------------ 64 | 65 | There is a final atomic output level, ``debug``, which behaves slightly 66 | differently from the rest: 67 | 68 | * **debug**: Turn on debugging (which is off by default.) Currently, this is 69 | largely used to view the "full" commands being run; take for example this 70 | `~fabric.operations.run` call:: 71 | 72 | run('ls "/home/username/Folder Name With Spaces/"') 73 | 74 | Normally, the ``running`` line will show exactly what is passed into 75 | `~fabric.operations.run`, like so:: 76 | 77 | [hostname] run: ls "/home/username/Folder Name With Spaces/" 78 | 79 | With ``debug`` on, and assuming you've left :ref:`shell` set to ``True``, you 80 | will see the literal, full string as passed to the remote server:: 81 | 82 | [hostname] run: /bin/bash -l -c "ls \"/home/username/Folder Name With Spaces\"" 83 | 84 | Enabling ``debug`` output will also display full Python tracebacks during 85 | aborts. 86 | 87 | .. note:: 88 | 89 | Where modifying other pieces of output (such as in the above example 90 | where it modifies the 'running' line to show the shell and any escape 91 | characters), this setting takes precedence over the others; so if 92 | ``running`` is False but ``debug`` is True, you will still be shown the 93 | 'running' line in its debugging form. 94 | 95 | .. versionchanged:: 1.0 96 | Debug output now includes full Python tracebacks during aborts. 97 | 98 | .. _output-aliases: 99 | 100 | Output level aliases 101 | -------------------- 102 | 103 | In addition to the atomic/standalone levels above, Fabric also provides a 104 | couple of convenience aliases which map to multiple other levels. These may be 105 | referenced anywhere the other levels are referenced, and will effectively 106 | toggle all of the levels they are mapped to. 107 | 108 | * **output**: Maps to both ``stdout`` and ``stderr``. Useful for when you only 109 | care to see the 'running' lines and your own print statements (and warnings). 110 | 111 | * **everything**: Includes ``warnings``, ``running``, ``user`` and ``output`` 112 | (see above.) Thus, when turning off ``everything``, you will only see a bare 113 | minimum of output (just ``status`` and ``debug`` if it's on), along with your 114 | own print statements. 115 | 116 | * **commands**: Includes ``stdout`` and ``running``. Good for hiding 117 | non-erroring commands entirely, while still displaying any stderr output. 118 | 119 | .. versionchanged:: 1.4 120 | Added the ``commands`` output alias. 121 | 122 | 123 | Hiding and/or showing output levels 124 | =================================== 125 | 126 | You may toggle any of Fabric's output levels in a number of ways; for examples, 127 | please see the API docs linked in each bullet point: 128 | 129 | * **Direct modification of fabric.state.output**: `fabric.state.output` is a 130 | dictionary subclass (similar to :doc:`env `) whose keys are the output 131 | level names, and whose values are either True (show that particular type of 132 | output) or False (hide it.) 133 | 134 | `fabric.state.output` is the lowest-level implementation of output levels and 135 | is what Fabric's internals reference when deciding whether or not to print 136 | their output. 137 | 138 | * **Context managers**: `~fabric.context_managers.hide` and 139 | `~fabric.context_managers.show` are twin context managers that take one or 140 | more output level names as strings, and either hide or show them within the 141 | wrapped block. As with Fabric's other context managers, the prior values are 142 | restored when the block exits. 143 | 144 | .. seealso:: 145 | 146 | `~fabric.context_managers.settings`, which can nest calls to 147 | `~fabric.context_managers.hide` and/or `~fabric.context_managers.show` 148 | inside itself. 149 | 150 | * **Command-line arguments**: You may use the :option:`--hide` and/or 151 | :option:`--show` arguments to :doc:`fab`, which behave exactly like the 152 | context managers of the same names (but are, naturally, globally applied) and 153 | take comma-separated strings as input. 154 | -------------------------------------------------------------------------------- /usage/parallel.rst: -------------------------------------------------------------------------------- 1 | ================== 2 | Parallel execution 3 | ================== 4 | 5 | .. _parallel-execution: 6 | 7 | .. versionadded:: 1.3 8 | 9 | By default, Fabric executes all specified tasks **serially** (see 10 | :ref:`execution-strategy` for details.) This document describes Fabric's 11 | options for running tasks on multiple hosts in **parallel**, via per-task 12 | decorators and/or global command-line switches. 13 | 14 | 15 | What it does 16 | ============ 17 | 18 | Because Fabric 1.x is not fully threadsafe (and because in general use, task 19 | functions do not typically interact with one another) this functionality is 20 | implemented via the Python `multiprocessing 21 | `_ module. It creates one 22 | new process for each host and task combination, optionally using a 23 | (configurable) sliding window to prevent too many processes from running at the 24 | same time. 25 | 26 | For example, imagine a scenario where you want to update Web application code 27 | on a number of Web servers, and then reload the servers once the code has been 28 | distributed everywhere (to allow for easier rollback if code updates fail.) One 29 | could implement this with the following fabfile:: 30 | 31 | from fabric.api import * 32 | 33 | def update(): 34 | with cd("/srv/django/myapp"): 35 | run("git pull") 36 | 37 | def reload(): 38 | sudo("service apache2 reload") 39 | 40 | and execute it on a set of 3 servers, in serial, like so:: 41 | 42 | $ fab -H web1,web2,web3 update reload 43 | 44 | Normally, without any parallel execution options activated, Fabric would run 45 | in order: 46 | 47 | #. ``update`` on ``web1`` 48 | #. ``update`` on ``web2`` 49 | #. ``update`` on ``web3`` 50 | #. ``reload`` on ``web1`` 51 | #. ``reload`` on ``web2`` 52 | #. ``reload`` on ``web3`` 53 | 54 | With parallel execution activated (via :option:`-P` -- see below for details), 55 | this turns into: 56 | 57 | #. ``update`` on ``web1``, ``web2``, and ``web3`` 58 | #. ``reload`` on ``web1``, ``web2``, and ``web3`` 59 | 60 | Hopefully the benefits of this are obvious -- if ``update`` took 5 seconds to 61 | run and ``reload`` took 2 seconds, serial execution takes (5+2)*3 = 21 seconds 62 | to run, while parallel execution takes only a third of the time, (5+2) = 7 63 | seconds on average. 64 | 65 | 66 | How to use it 67 | ============= 68 | 69 | Decorators 70 | ---------- 71 | 72 | Since the minimum "unit" that parallel execution affects is a task, the 73 | functionality may be enabled or disabled on a task-by-task basis using the 74 | `~fabric.decorators.parallel` and `~fabric.decorators.serial` decorators. For 75 | example, this fabfile:: 76 | 77 | from fabric.api import * 78 | 79 | @parallel 80 | def runs_in_parallel(): 81 | pass 82 | 83 | def runs_serially(): 84 | pass 85 | 86 | when run in this manner:: 87 | 88 | $ fab -H host1,host2,host3 runs_in_parallel runs_serially 89 | 90 | will result in the following execution sequence: 91 | 92 | #. ``runs_in_parallel`` on ``host1``, ``host2``, and ``host3`` 93 | #. ``runs_serially`` on ``host1`` 94 | #. ``runs_serially`` on ``host2`` 95 | #. ``runs_serially`` on ``host3`` 96 | 97 | Command-line flags 98 | ------------------ 99 | 100 | One may also force all tasks to run in parallel by using the command-line flag 101 | :option:`-P` or the env variable :ref:`env.parallel `. However, 102 | any task specifically wrapped with `~fabric.decorators.serial` will ignore this 103 | setting and continue to run serially. 104 | 105 | For example, the following fabfile will result in the same execution sequence 106 | as the one above:: 107 | 108 | from fabric.api import * 109 | 110 | def runs_in_parallel(): 111 | pass 112 | 113 | @serial 114 | def runs_serially(): 115 | pass 116 | 117 | when invoked like so:: 118 | 119 | $ fab -H host1,host2,host3 -P runs_in_parallel runs_serially 120 | 121 | As before, ``runs_in_parallel`` will run in parallel, and ``runs_serially`` in 122 | sequence. 123 | 124 | 125 | Bubble size 126 | =========== 127 | 128 | With large host lists, a user's local machine can get overwhelmed by running 129 | too many concurrent Fabric processes. Because of this, you may opt to use a 130 | moving bubble approach that limits Fabric to a specific number of concurrently 131 | active processes. 132 | 133 | By default, no bubble is used and all hosts are run in one concurrent pool. You 134 | can override this on a per-task level by specifying the ``pool_size`` keyword 135 | argument to `~fabric.decorators.parallel`, or globally via :option:`-z`. 136 | 137 | For example, to run on 5 hosts at a time:: 138 | 139 | from fabric.api import * 140 | 141 | @parallel(pool_size=5) 142 | def heavy_task(): 143 | # lots of heavy local lifting or lots of IO here 144 | 145 | Or skip the ``pool_size`` kwarg and instead:: 146 | 147 | $ fab -P -z 5 heavy_task 148 | 149 | .. _linewise-output: 150 | 151 | Linewise vs bytewise output 152 | =========================== 153 | 154 | Fabric's default mode of printing to the terminal is byte-by-byte, in order to 155 | support :doc:`/usage/interactivity`. This often gives poor results when running 156 | in parallel mode, as the multiple processes may write to your terminal's 157 | standard out stream simultaneously. 158 | 159 | To help offset this problem, Fabric's option for linewise output is 160 | automatically enabled whenever parallelism is active. This will cause you to 161 | lose most of the benefits outlined in the above link Fabric's remote 162 | interactivity features, but as those do not map well to parallel invocations, 163 | it's typically a fair trade. 164 | 165 | There's no way to avoid the multiple processes mixing up on a line-by-line 166 | basis, but you will at least be able to tell them apart by the host-string line 167 | prefix. 168 | 169 | .. note:: 170 | Future versions will add improved logging support to make troubleshooting 171 | parallel runs easier. 172 | -------------------------------------------------------------------------------- /usage/ssh.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | SSH behavior 3 | ============ 4 | 5 | Fabric currently makes use of a pure-Python SSH re-implementation for managing 6 | connections, meaning that there are occasionally spots where it is limited by 7 | that library's capabilities. Below are areas of note where Fabric will exhibit 8 | behavior that isn't consistent with, or as flexible as, the behavior of the 9 | ``ssh`` command-line program. 10 | 11 | 12 | Unknown hosts 13 | ============= 14 | 15 | SSH's host key tracking mechanism keeps tabs on all the hosts you attempt to 16 | connect to, and maintains a ``~/.ssh/known_hosts`` file with mappings between 17 | identifiers (IP address, sometimes with a hostname as well) and SSH keys. (For 18 | details on how this works, please see the `OpenSSH documentation 19 | `_.) 20 | 21 | The ``paramiko`` library is capable of loading up your ``known_hosts`` file, 22 | and will then compare any host it connects to, with that mapping. Settings are 23 | available to determine what happens when an unknown host (a host whose username 24 | or IP is not found in ``known_hosts``) is seen: 25 | 26 | * **Reject**: the host key is rejected and the connection is not made. This 27 | results in a Python exception, which will terminate your Fabric session with a 28 | message that the host is unknown. 29 | * **Add**: the new host key is added to the in-memory list of known hosts, the 30 | connection is made, and things continue normally. Note that this does **not** 31 | modify your on-disk ``known_hosts`` file! 32 | * **Ask**: not yet implemented at the Fabric level, this is a ``paramiko`` 33 | library option which would result in the user being prompted about the 34 | unknown key and whether to accept it. 35 | 36 | Whether to reject or add hosts, as above, is controlled in Fabric via the 37 | :ref:`env.reject_unknown_hosts ` option, which is False 38 | by default for convenience's sake. We feel this is a valid tradeoff between 39 | convenience and security; anyone who feels otherwise can easily modify their 40 | fabfiles at module level to set ``env.reject_unknown_hosts = True``. 41 | 42 | 43 | Known hosts with changed keys 44 | ============================= 45 | 46 | The point of SSH's key/fingerprint tracking is so that man-in-the-middle 47 | attacks can be detected: if an attacker redirects your SSH traffic to a 48 | computer under his control, and pretends to be your original destination 49 | server, the host keys will not match. Thus, the default behavior of SSH (and 50 | its Python implementation) is to immediately abort the connection when a host 51 | previously recorded in ``known_hosts`` suddenly starts sending us a different 52 | host key. 53 | 54 | In some edge cases such as some EC2 deployments, you may want to ignore this 55 | potential problem. Our SSH layer, at the time of writing, doesn't give us 56 | control over this exact behavior, but we can sidestep it by simply skipping the 57 | loading of ``known_hosts`` -- if the host list being compared to is empty, then 58 | there's no problem. Set :ref:`env.disable_known_hosts ` to 59 | True when you want this behavior; it is False by default, in order to preserve 60 | default SSH behavior. 61 | 62 | .. warning:: 63 | Enabling :ref:`env.disable_known_hosts ` will leave 64 | you wide open to man-in-the-middle attacks! Please use with caution. 65 | -------------------------------------------------------------------------------- /usage/tasks.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Defining tasks 3 | ============== 4 | 5 | As of Fabric 1.1, there are two distinct methods you may use in order to define 6 | which objects in your fabfile show up as tasks: 7 | 8 | * The "new" method starting in 1.1 considers instances of `~fabric.tasks.Task` 9 | or its subclasses, and also descends into imported modules to allow building 10 | nested namespaces. 11 | * The "classic" method from 1.0 and earlier considers all public callable 12 | objects (functions, classes etc) and only considers the objects in the 13 | fabfile itself with no recursing into imported module. 14 | 15 | .. note:: 16 | These two methods are **mutually exclusive**: if Fabric finds *any* 17 | new-style task objects in your fabfile or in modules it imports, it will 18 | assume you've committed to this method of task declaration and won't 19 | consider any non-`~fabric.tasks.Task` callables. If *no* new-style tasks 20 | are found, it reverts to the classic behavior. 21 | 22 | The rest of this document explores these two methods in detail. 23 | 24 | .. note:: 25 | 26 | To see exactly what tasks in your fabfile may be executed via ``fab``, use 27 | :option:`fab --list <-l>`. 28 | 29 | .. _new-style-tasks: 30 | 31 | New-style tasks 32 | =============== 33 | 34 | Fabric 1.1 introduced the `~fabric.tasks.Task` class to facilitate new features 35 | and enable some programming best practices, specifically: 36 | 37 | * **Object-oriented tasks**. Inheritance and all that comes with it can make 38 | for much more sensible code reuse than passing around simple function 39 | objects. The classic style of task declaration didn't entirely rule this 40 | out, but it also didn't make it terribly easy. 41 | * **Namespaces**. Having an explicit method of declaring tasks makes it easier 42 | to set up recursive namespaces without e.g. polluting your task list with the 43 | contents of Python's ``os`` module (which would show up as valid "tasks" 44 | under the classic methodology.) 45 | 46 | With the introduction of `~fabric.tasks.Task`, there are two ways to set up new 47 | tasks: 48 | 49 | * Decorate a regular module level function with `@task 50 | `, which transparently wraps the function in a 51 | `~fabric.tasks.Task` subclass. The function name will be used as the task 52 | name when invoking. 53 | * Subclass `~fabric.tasks.Task` (`~fabric.tasks.Task` itself is intended to be 54 | abstract), define a ``run`` method, and instantiate your subclass at module 55 | level. Instances' ``name`` attributes are used as the task name; if omitted 56 | the instance's variable name will be used instead. 57 | 58 | Use of new-style tasks also allows you to set up :ref:`namespaces 59 | `. 60 | 61 | 62 | .. _task-decorator: 63 | 64 | The ``@task`` decorator 65 | ----------------------- 66 | 67 | The quickest way to make use of new-style task features is to wrap basic task functions with `@task `:: 68 | 69 | from fabric.api import task, run 70 | 71 | @task 72 | def mytask(): 73 | run("a command") 74 | 75 | 76 | When this decorator is used, it signals to Fabric that *only* functions wrapped in the decorator are to be loaded up as valid tasks. (When not present, :ref:`classic-style task ` behavior kicks in.) 77 | 78 | .. _task-decorator-arguments: 79 | 80 | Arguments 81 | ~~~~~~~~~ 82 | 83 | `@task ` may also be called with arguments to 84 | customize its behavior. Any arguments not documented below are passed into the 85 | constructor of the ``task_class`` being used, with the function itself as the 86 | first argument (see :ref:`task-decorator-and-classes` for details.) 87 | 88 | * ``task_class``: The `~fabric.tasks.Task` subclass used to wrap the decorated 89 | function. Defaults to `~fabric.tasks.WrappedCallableTask`. 90 | * ``aliases``: An iterable of string names which will be used as aliases for 91 | the wrapped function. See :ref:`task-aliases` for details. 92 | * ``alias``: Like ``aliases`` but taking a single string argument instead of an 93 | iterable. If both ``alias`` and ``aliases`` are specified, ``aliases`` will 94 | take precedence. 95 | * ``default``: A boolean value determining whether the decorated task also 96 | stands in for its containing module as a task name. See :ref:`default-tasks`. 97 | * ``name``: A string setting the name this task appears as to the command-line 98 | interface. Useful for task names that would otherwise shadow Python builtins 99 | (which is technically legal but frowned upon and bug-prone.) 100 | 101 | .. _task-aliases: 102 | 103 | Aliases 104 | ~~~~~~~ 105 | 106 | Here's a quick example of using the ``alias`` keyword argument to facilitate 107 | use of both a longer human-readable task name, and a shorter name which is 108 | quicker to type:: 109 | 110 | from fabric.api import task 111 | 112 | @task(alias='dwm') 113 | def deploy_with_migrations(): 114 | pass 115 | 116 | Calling :option:`--list <-l>` on this fabfile would show both the original 117 | ``deploy_with_migrations`` and its alias ``dwm``:: 118 | 119 | $ fab --list 120 | Available commands: 121 | 122 | deploy_with_migrations 123 | dwm 124 | 125 | When more than one alias for the same function is needed, simply swap in the 126 | ``aliases`` kwarg, which takes an iterable of strings instead of a single 127 | string. 128 | 129 | .. _default-tasks: 130 | 131 | Default tasks 132 | ~~~~~~~~~~~~~ 133 | 134 | In a similar manner to :ref:`aliases `, it's sometimes useful to 135 | designate a given task within a module as the "default" task, which may be 136 | called by referencing *just* the module name. This can save typing and/or 137 | allow for neater organization when there's a single "main" task and a number 138 | of related tasks or subroutines. 139 | 140 | For example, a ``deploy`` submodule might contain tasks for provisioning new 141 | servers, pushing code, migrating databases, and so forth -- but it'd be very 142 | convenient to highlight a task as the default "just deploy" action. Such a 143 | ``deploy.py`` module might look like this:: 144 | 145 | from fabric.api import task 146 | 147 | @task 148 | def migrate(): 149 | pass 150 | 151 | @task 152 | def push(): 153 | pass 154 | 155 | @task 156 | def provision(): 157 | pass 158 | 159 | @task 160 | def full_deploy(): 161 | if not provisioned: 162 | provision() 163 | push() 164 | migrate() 165 | 166 | With the following task list (assuming a simple top level ``fabfile.py`` that just imports ``deploy``):: 167 | 168 | $ fab --list 169 | Available commands: 170 | 171 | deploy.full_deploy 172 | deploy.migrate 173 | deploy.provision 174 | deploy.push 175 | 176 | Calling ``deploy.full_deploy`` on every deploy could get kind of old, or somebody new to the team might not be sure if that's really the right task to run. 177 | 178 | Using the ``default`` kwarg to `@task `, we can tag 179 | e.g. ``full_deploy`` as the default task:: 180 | 181 | @task(default=True) 182 | def full_deploy(): 183 | pass 184 | 185 | Doing so updates the task list like so:: 186 | 187 | $ fab --list 188 | Available commands: 189 | 190 | deploy 191 | deploy.full_deploy 192 | deploy.migrate 193 | deploy.provision 194 | deploy.push 195 | 196 | Note that ``full_deploy`` still exists as its own explicit task -- but now 197 | ``deploy`` shows up as a sort of top level alias for ``full_deploy``. 198 | 199 | If multiple tasks within a module have ``default=True`` set, the last one to 200 | be loaded (typically the one lowest down in the file) will take precedence. 201 | 202 | Top-level default tasks 203 | ~~~~~~~~~~~~~~~~~~~~~~~ 204 | 205 | Using ``@task(default=True)`` in the top level fabfile will cause the denoted 206 | task to execute when a user invokes ``fab`` without any task names (similar to 207 | e.g. ``make``.) When using this shortcut, it is not possible to specify 208 | arguments to the task itself -- use a regular invocation of the task if this 209 | is necessary. 210 | 211 | .. _task-subclasses: 212 | 213 | ``Task`` subclasses 214 | ------------------- 215 | 216 | If you're used to :ref:`classic-style tasks `, an easy way to 217 | think about `~fabric.tasks.Task` subclasses is that their ``run`` method is 218 | directly equivalent to a classic task; its arguments are the task arguments 219 | (other than ``self``) and its body is what gets executed. 220 | 221 | For example, this new-style task:: 222 | 223 | class MyTask(Task): 224 | name = "deploy" 225 | def run(self, environment, domain="whatever.com"): 226 | run("git clone foo") 227 | sudo("service apache2 restart") 228 | 229 | instance = MyTask() 230 | 231 | is exactly equivalent to this function-based task:: 232 | 233 | @task 234 | def deploy(environment, domain="whatever.com"): 235 | run("git clone foo") 236 | sudo("service apache2 restart") 237 | 238 | Note how we had to instantiate an instance of our class; that's simply normal 239 | Python object-oriented programming at work. While it's a small bit of 240 | boilerplate right now -- for example, Fabric doesn't care about the name you 241 | give the instantiation, only the instance's ``name`` attribute -- it's well 242 | worth the benefit of having the power of classes available. 243 | 244 | We plan to extend the API in the future to make this experience a bit smoother. 245 | 246 | .. _task-decorator-and-classes: 247 | 248 | Using custom subclasses with ``@task`` 249 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 250 | 251 | It's possible to marry custom `~fabric.tasks.Task` subclasses with `@task 252 | `. This may be useful in cases where your core 253 | execution logic doesn't do anything class/object-specific, but you want to 254 | take advantage of class metaprogramming or similar techniques. 255 | 256 | Specifically, any `~fabric.tasks.Task` subclass which is designed to take in a 257 | callable as its first constructor argument (as the built-in 258 | `~fabric.tasks.WrappedCallableTask` does) may be specified as the 259 | ``task_class`` argument to `@task `. 260 | 261 | Fabric will automatically instantiate a copy of the given class, passing in 262 | the wrapped function as the first argument. All other args/kwargs given to the 263 | decorator (besides the "special" arguments documented in 264 | :ref:`task-decorator-arguments`) are added afterwards. 265 | 266 | Here's a brief and somewhat contrived example to make this obvious:: 267 | 268 | from fabric.api import task 269 | from fabric.tasks import Task 270 | 271 | class CustomTask(Task): 272 | def __init__(self, func, myarg, *args, **kwargs): 273 | super(CustomTask, self).__init__(*args, **kwargs) 274 | self.func = func 275 | self.myarg = myarg 276 | 277 | def run(self, *args, **kwargs): 278 | return self.func(*args, **kwargs) 279 | 280 | @task(task_class=CustomTask, myarg='value', alias='at') 281 | def actual_task(): 282 | pass 283 | 284 | When this fabfile is loaded, a copy of ``CustomTask`` is instantiated, effectively calling:: 285 | 286 | task_obj = CustomTask(actual_task, myarg='value') 287 | 288 | Note how the ``alias`` kwarg is stripped out by the decorator itself and never 289 | reaches the class instantiation; this is identical in function to how 290 | :ref:`command-line task arguments ` work. 291 | 292 | .. _namespaces: 293 | 294 | Namespaces 295 | ---------- 296 | 297 | With :ref:`classic tasks `, fabfiles were limited to a single, 298 | flat set of task names with no real way to organize them. In Fabric 1.1 and 299 | newer, if you declare tasks the new way (via `@task ` 300 | or your own `~fabric.tasks.Task` subclass instances) you may take advantage 301 | of **namespacing**: 302 | 303 | * Any module objects imported into your fabfile will be recursed into, looking 304 | for additional task objects. 305 | * Within submodules, you may control which objects are "exported" by using the 306 | standard Python ``__all__`` module-level variable name (thought they should 307 | still be valid new-style task objects.) 308 | * These tasks will be given new dotted-notation names based on the modules they 309 | came from, similar to Python's own import syntax. 310 | 311 | Let's build up a fabfile package from simple to complex and see how this works. 312 | 313 | Basic 314 | ~~~~~ 315 | 316 | We start with a single `__init__.py` containing a few tasks (the Fabric API 317 | import omitted for brevity):: 318 | 319 | @task 320 | def deploy(): 321 | ... 322 | 323 | @task 324 | def compress(): 325 | ... 326 | 327 | The output of ``fab --list`` would look something like this:: 328 | 329 | deploy 330 | compress 331 | 332 | There's just one namespace here: the "root" or global namespace. Looks simple 333 | now, but in a real-world fabfile with dozens of tasks, it can get difficult to 334 | manage. 335 | 336 | Importing a submodule 337 | ~~~~~~~~~~~~~~~~~~~~~ 338 | 339 | As mentioned above, Fabric will examine any imported module objects for tasks, 340 | regardless of where that module exists on your Python import path. For now we 341 | just want to include our own, "nearby" tasks, so we'll make a new submodule in 342 | our package for dealing with, say, load balancers -- ``lb.py``:: 343 | 344 | @task 345 | def add_backend(): 346 | ... 347 | 348 | And we'll add this to the top of ``__init__.py``:: 349 | 350 | import lb 351 | 352 | Now ``fab --list`` shows us:: 353 | 354 | deploy 355 | compress 356 | lb.add_backend 357 | 358 | Again, with only one task in its own submodule, it looks kind of silly, but the 359 | benefits should be pretty obvious. 360 | 361 | Going deeper 362 | ~~~~~~~~~~~~ 363 | 364 | Namespacing isn't limited to just one level. Let's say we had a larger setup 365 | and wanted a namespace for database related tasks, with additional 366 | differentiation inside that. We make a sub-package named ``db/`` and inside it, 367 | a ``migrations.py`` module:: 368 | 369 | @task 370 | def list(): 371 | ... 372 | 373 | @task 374 | def run(): 375 | ... 376 | 377 | We need to make sure that this module is visible to anybody importing ``db``, 378 | so we add it to the sub-package's ``__init__.py``:: 379 | 380 | import migrations 381 | 382 | As a final step, we import the sub-package into our root-level ``__init__.py``, 383 | so now its first few lines look like this:: 384 | 385 | import lb 386 | import db 387 | 388 | After all that, our file tree looks like this:: 389 | 390 | . 391 | ├── __init__.py 392 | ├── db 393 | │   ├── __init__.py 394 | │   └── migrations.py 395 | └── lb.py 396 | 397 | and ``fab --list`` shows:: 398 | 399 | deploy 400 | compress 401 | lb.add_backend 402 | db.migrations.list 403 | db.migrations.run 404 | 405 | We could also have specified (or imported) tasks directly into 406 | ``db/__init__.py``, and they would show up as ``db.`` as you might 407 | expect. 408 | 409 | Limiting with ``__all__`` 410 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 411 | 412 | You may limit what Fabric "sees" when it examines imported modules, by using 413 | the Python convention of a module level ``__all__`` variable (a list of 414 | variable names.) If we didn't want the ``db.migrations.run`` task to show up by 415 | default for some reason, we could add this to the top of ``db/migrations.py``:: 416 | 417 | __all__ = ['list'] 418 | 419 | Note the lack of ``'run'`` there. You could, if needed, import ``run`` directly 420 | into some other part of the hierarchy, but otherwise it'll remain hidden. 421 | 422 | Switching it up 423 | ~~~~~~~~~~~~~~~ 424 | 425 | We've been keeping our fabfile package neatly organized and importing it in a 426 | straightforward manner, but the filesystem layout doesn't actually matter here. 427 | All Fabric's loader cares about is the names the modules are given when they're 428 | imported. 429 | 430 | For example, if we changed the top of our root ``__init__.py`` to look like 431 | this:: 432 | 433 | import db as database 434 | 435 | Our task list would change thusly:: 436 | 437 | deploy 438 | compress 439 | lb.add_backend 440 | database.migrations.list 441 | database.migrations.run 442 | 443 | This applies to any other import -- you could import third party modules into 444 | your own task hierarchy, or grab a deeply nested module and make it appear near 445 | the top level. 446 | 447 | Nested list output 448 | ~~~~~~~~~~~~~~~~~~ 449 | 450 | As a final note, we've been using the default Fabric :option:`--list <-l>` 451 | output during this section -- it makes it more obvious what the actual task 452 | names are. However, you can get a more nested or tree-like view by passing 453 | ``nested`` to the :option:`--list-format <-F>` option:: 454 | 455 | $ fab --list-format=nested --list 456 | Available commands (remember to call as module.[...].task): 457 | 458 | deploy 459 | compress 460 | lb: 461 | add_backend 462 | database: 463 | migrations: 464 | list 465 | run 466 | 467 | While it slightly obfuscates the "real" task names, this view provides a handy 468 | way of noting the organization of tasks in large namespaces. 469 | 470 | 471 | .. _classic-tasks: 472 | 473 | Classic tasks 474 | ============= 475 | 476 | When no new-style `~fabric.tasks.Task`-based tasks are found, Fabric will 477 | consider any callable object found in your fabfile, **except** the following: 478 | 479 | * Callables whose name starts with an underscore (``_``). In other words, 480 | Python's usual "private" convention holds true here. 481 | * Callables defined within Fabric itself. Fabric's own functions such as 482 | `~fabric.operations.run` and `~fabric.operations.sudo` will not show up in 483 | your task list. 484 | 485 | 486 | Imports 487 | ------- 488 | 489 | Python's ``import`` statement effectively includes the imported objects in your 490 | module's namespace. Since Fabric's fabfiles are just Python modules, this means 491 | that imports are also considered as possible classic-style tasks, alongside 492 | anything defined in the fabfile itself. 493 | 494 | .. note:: 495 | This only applies to imported *callable objects* -- not modules. 496 | Imported modules only come into play if they contain :ref:`new-style 497 | tasks `, at which point this section no longer 498 | applies. 499 | 500 | Because of this, we strongly recommend that you use the ``import module`` form 501 | of importing, followed by ``module.callable()``, which will result in a cleaner 502 | fabfile API than doing ``from module import callable``. 503 | 504 | For example, here's a sample fabfile which uses ``urllib.urlopen`` to get some 505 | data out of a webservice:: 506 | 507 | from urllib import urlopen 508 | 509 | from fabric.api import run 510 | 511 | def webservice_read(): 512 | objects = urlopen('http://my/web/service/?foo=bar').read().split() 513 | print(objects) 514 | 515 | This looks simple enough, and will run without error. However, look what 516 | happens if we run :option:`fab --list <-l>` on this fabfile:: 517 | 518 | $ fab --list 519 | Available commands: 520 | 521 | webservice_read List some directories. 522 | urlopen urlopen(url [, data]) -> open file-like object 523 | 524 | Our fabfile of only one task is showing two "tasks", which is bad enough, and 525 | an unsuspecting user might accidentally try to call ``fab urlopen``, which 526 | probably won't work very well. Imagine any real-world fabfile, which is likely 527 | to be much more complex, and hopefully you can see how this could get messy 528 | fast. 529 | 530 | For reference, here's the recommended way to do it:: 531 | 532 | import urllib 533 | 534 | from fabric.api import run 535 | 536 | def webservice_read(): 537 | objects = urllib.urlopen('http://my/web/service/?foo=bar').read().split() 538 | print(objects) 539 | 540 | It's a simple change, but it'll make anyone using your fabfile a bit happier. 541 | --------------------------------------------------------------------------------