conf.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. # pylint: disable=C0103,W0622
  2. """
  3. Sphinx documentation for Salt
  4. """
  5. import os
  6. import re
  7. import sys
  8. import time
  9. import types
  10. from sphinx.directives.other import TocTree
  11. class Mock:
  12. """
  13. Mock out specified imports.
  14. This allows autodoc to do its thing without having oodles of req'd
  15. installed libs. This doesn't work with ``import *`` imports.
  16. This Mock class can be configured to return a specific values at specific names, if required.
  17. https://read-the-docs.readthedocs.io/en/latest/faq.html#i-get-import-errors-on-libraries-that-depend-on-c-modules
  18. """
  19. def __init__(
  20. self, mapping=None, *args, **kwargs
  21. ): # pylint: disable=unused-argument
  22. """
  23. Mapping allows autodoc to bypass the Mock object, but actually assign
  24. a specific value, expected by a specific attribute returned.
  25. """
  26. self.__mapping = mapping or {}
  27. __all__ = []
  28. def __call__(self, *args, **kwargs):
  29. # If mocked function is used as a decorator, expose decorated function.
  30. # if args and callable(args[-1]):
  31. # functools.update_wrapper(ret, args[0])
  32. return Mock(mapping=self.__mapping)
  33. def __getattr__(self, name):
  34. if name in self.__mapping:
  35. data = self.__mapping.get(name)
  36. elif name in ("__file__", "__path__"):
  37. data = "/dev/null"
  38. elif name in ("__mro_entries__", "__qualname__"):
  39. raise AttributeError("'Mock' object has no attribute '%s'" % (name))
  40. else:
  41. data = Mock(mapping=self.__mapping)
  42. return data
  43. def __iter__(self):
  44. return self
  45. @staticmethod
  46. def __next__():
  47. raise StopIteration
  48. # For Python 2
  49. next = __next__
  50. def mock_decorator_with_params(*oargs, **okwargs): # pylint: disable=unused-argument
  51. """
  52. Optionally mock a decorator that takes parameters
  53. E.g.:
  54. @blah(stuff=True)
  55. def things():
  56. pass
  57. """
  58. def inner(fn, *iargs, **ikwargs): # pylint: disable=unused-argument
  59. if hasattr(fn, "__call__"):
  60. return fn
  61. return Mock()
  62. return inner
  63. MOCK_MODULES = [
  64. # Python stdlib
  65. "user",
  66. # salt core
  67. "Crypto",
  68. "Crypto.Signature",
  69. "Crypto.Cipher",
  70. "Crypto.Hash",
  71. "Crypto.PublicKey",
  72. "Crypto.Random",
  73. "Crypto.Signature",
  74. "Crypto.Signature.PKCS1_v1_5",
  75. "distro",
  76. "M2Crypto",
  77. "msgpack",
  78. "yaml",
  79. "yaml.constructor",
  80. "yaml.nodes",
  81. "yaml.parser",
  82. "yaml.scanner",
  83. "zmq",
  84. "zmq.eventloop",
  85. "zmq.eventloop.ioloop",
  86. # third-party libs for cloud modules
  87. "libcloud",
  88. "libcloud.compute",
  89. "libcloud.compute.base",
  90. "libcloud.compute.deployment",
  91. "libcloud.compute.providers",
  92. "libcloud.compute.types",
  93. "libcloud.loadbalancer",
  94. "libcloud.loadbalancer.types",
  95. "libcloud.loadbalancer.providers",
  96. "libcloud.common",
  97. "libcloud.common.google",
  98. # third-party libs for netapi modules
  99. "cherrypy",
  100. "cherrypy.lib",
  101. "cherrypy.process",
  102. "cherrypy.wsgiserver",
  103. "cherrypy.wsgiserver.ssl_builtin",
  104. "tornado",
  105. "tornado.concurrent",
  106. "tornado.escape",
  107. "tornado.gen",
  108. "tornado.httpclient",
  109. "tornado.httpserver",
  110. "tornado.httputil",
  111. "tornado.ioloop",
  112. "tornado.iostream",
  113. "tornado.netutil",
  114. "tornado.simple_httpclient",
  115. "tornado.stack_context",
  116. "tornado.web",
  117. "tornado.websocket",
  118. "tornado.locks",
  119. "ws4py",
  120. "ws4py.server",
  121. "ws4py.server.cherrypyserver",
  122. "ws4py.websocket",
  123. # modules, renderers, states, returners, et al
  124. "ClusterShell",
  125. "ClusterShell.NodeSet",
  126. "MySQLdb",
  127. "MySQLdb.cursors",
  128. "OpenSSL",
  129. "avahi",
  130. "boto.regioninfo",
  131. "dbus",
  132. "django",
  133. "dns",
  134. "dns.resolver",
  135. "dson",
  136. "hjson",
  137. "jnpr",
  138. "jnpr.junos",
  139. "jnpr.junos.utils",
  140. "jnpr.junos.utils.config",
  141. "jnpr.junos.utils.sw",
  142. "keyring",
  143. "kubernetes",
  144. "kubernetes.config",
  145. "libvirt",
  146. "lxml",
  147. "lxml.etree",
  148. "msgpack",
  149. "nagios_json",
  150. "napalm",
  151. "netaddr",
  152. "netaddr.IPAddress",
  153. "netaddr.core",
  154. "netaddr.core.AddrFormatError",
  155. "ntsecuritycon",
  156. "psutil",
  157. "pycassa",
  158. "pyconnman",
  159. "pyiface",
  160. "pymongo",
  161. "pyroute2",
  162. "pyroute2.ipdb",
  163. "rabbitmq_server",
  164. "redis",
  165. "rpm",
  166. "rpmUtils",
  167. "rpmUtils.arch",
  168. "salt.ext.six.moves.winreg",
  169. "twisted",
  170. "twisted.internet",
  171. "twisted.internet.protocol",
  172. "twisted.internet.protocol.DatagramProtocol",
  173. "win32security",
  174. "yum",
  175. "zfs",
  176. ]
  177. MOCK_MODULES_MAPPING = {
  178. "cherrypy": {"config": mock_decorator_with_params},
  179. "ntsecuritycon": {"STANDARD_RIGHTS_REQUIRED": 0, "SYNCHRONIZE": 0,},
  180. "psutil": {"total": 0}, # Otherwise it will crash Sphinx
  181. }
  182. for mod_name in MOCK_MODULES:
  183. sys.modules[mod_name] = Mock(mapping=MOCK_MODULES_MAPPING.get(mod_name))
  184. # Define a fake version attribute for the following libs.
  185. sys.modules["libcloud"].__version__ = "0.0.0"
  186. sys.modules["msgpack"].version = (1, 0, 0)
  187. sys.modules["psutil"].version_info = (3, 0, 0)
  188. sys.modules["pymongo"].version = "0.0.0"
  189. sys.modules["tornado"].version_info = (0, 0, 0)
  190. sys.modules["boto.regioninfo"]._load_json_file = {"endpoints": None}
  191. # -- Add paths to PYTHONPATH ---------------------------------------------------
  192. try:
  193. docs_basepath = os.path.abspath(os.path.dirname(__file__))
  194. except NameError:
  195. # sphinx-intl and six execute some code which will raise this NameError
  196. # assume we're in the doc/ directory
  197. docs_basepath = os.path.abspath(os.path.dirname("."))
  198. addtl_paths = (
  199. os.pardir, # salt itself (for autodoc)
  200. "_ext", # custom Sphinx extensions
  201. )
  202. for addtl_path in addtl_paths:
  203. sys.path.insert(0, os.path.abspath(os.path.join(docs_basepath, addtl_path)))
  204. # We're now able to import salt
  205. import salt.version # isort:skip
  206. formulas_dir = os.path.join(os.pardir, docs_basepath, "formulas")
  207. # ----- Intersphinx Settings ------------------------------------------------>
  208. intersphinx_mapping = {"python": ("https://docs.python.org/3", None)}
  209. # <---- Intersphinx Settings -------------------------------------------------
  210. # -- General Configuration -----------------------------------------------------
  211. # Set a var if we're building docs for the live site or not
  212. on_saltstack = "SALT_ON_SALTSTACK" in os.environ
  213. project = "Salt"
  214. repo_primary_branch = (
  215. "master" # This is the default branch on GitHub for the Salt project
  216. )
  217. version = salt.version.__version__
  218. latest_release = os.environ.get(
  219. "LATEST_RELEASE", "latest_release"
  220. ) # latest release (2019.2.3)
  221. previous_release = os.environ.get(
  222. "PREVIOUS_RELEASE", "previous_release"
  223. ) # latest release from previous branch (2018.3.5)
  224. previous_release_dir = os.environ.get(
  225. "PREVIOUS_RELEASE_DIR", "previous_release_dir"
  226. ) # path on web server for previous branch (2018.3)
  227. next_release = "" # next release
  228. next_release_dir = "" # path on web server for next release branch
  229. today = ""
  230. copyright = ""
  231. if on_saltstack:
  232. today = (
  233. "Generated on "
  234. + time.strftime("%B %d, %Y")
  235. + " at "
  236. + time.strftime("%X %Z")
  237. + "."
  238. )
  239. copyright = time.strftime("%Y")
  240. # < --- START do not merge these settings to other branches START ---> #
  241. build_type = os.environ.get(
  242. "BUILD_TYPE", repo_primary_branch
  243. ) # latest, previous, master, next
  244. # < --- END do not merge these settings to other branches END ---> #
  245. # Set google custom search engine
  246. if build_type == repo_primary_branch:
  247. release = latest_release
  248. search_cx = "011515552685726825874:v1had6i279q" # master
  249. # search_cx = '011515552685726825874:x17j5zl74g8' # develop
  250. elif build_type == "next":
  251. release = next_release
  252. search_cx = "011515552685726825874:ht0p8miksrm" # latest
  253. elif build_type == "previous":
  254. release = previous_release
  255. if release.startswith("3003"):
  256. search_cx = "a70a1a73eef62aecd" # 3003
  257. elif release.startswith("3002"):
  258. search_cx = "5026f4f2af0bdbe2d" # 3002
  259. elif release.startswith("3001"):
  260. search_cx = "f0e4f298fa32b8a5e" # 3001
  261. elif release.startswith("3000"):
  262. search_cx = "011515552685726825874:3skhaozjtyn" # 3000
  263. elif release.startswith("2019.2"):
  264. search_cx = "011515552685726825874:huvjhlpptnm" # 2019.2
  265. elif release.startswith("2018.3"):
  266. search_cx = "011515552685726825874:vadptdpvyyu" # 2018.3
  267. elif release.startswith("2017.7"):
  268. search_cx = "011515552685726825874:w-hxmnbcpou" # 2017.7
  269. elif release.startswith("2016.11"):
  270. search_cx = "011515552685726825874:dlsj745pvhq" # 2016.11
  271. else:
  272. search_cx = "011515552685726825874:ht0p8miksrm" # latest
  273. else: # latest or something else
  274. release = latest_release
  275. search_cx = "011515552685726825874:ht0p8miksrm" # latest
  276. needs_sphinx = "1.3"
  277. spelling_lang = "en_US"
  278. language = "en"
  279. locale_dirs = [
  280. "_locale",
  281. ]
  282. master_doc = "contents"
  283. templates_path = ["_templates"]
  284. exclude_patterns = ["_build", "_incl/*", "ref/cli/_includes/*.rst"]
  285. extensions = [
  286. "saltdomain", # Must come early
  287. "sphinx.ext.autodoc",
  288. "sphinx.ext.napoleon",
  289. "sphinx.ext.autosummary",
  290. "sphinx.ext.extlinks",
  291. "sphinx.ext.intersphinx",
  292. "httpdomain",
  293. "youtube",
  294. "saltrepo"
  295. #'saltautodoc', # Must be AFTER autodoc
  296. #'shorturls',
  297. ]
  298. try:
  299. import sphinxcontrib.spelling # false positive, pylint: disable=unused-import
  300. except ImportError:
  301. pass
  302. else:
  303. extensions += ["sphinxcontrib.spelling"]
  304. modindex_common_prefix = ["salt."]
  305. autosummary_generate = True
  306. autosummary_generate_overwrite = False
  307. # strip git rev as there won't necessarily be a release based on it
  308. stripped_release = re.sub(r"-\d+-g[0-9a-f]+$", "", release)
  309. # Define a substitution for linking to the latest release tarball
  310. rst_prolog = """\
  311. .. |current_release_doc| replace:: :doc:`/topics/releases/{release}`
  312. .. |saltrepo| replace:: https://github.com/saltstack/salt
  313. .. _`salt-users`: https://groups.google.com/forum/#!forum/salt-users
  314. .. _`salt-announce`: https://groups.google.com/forum/#!forum/salt-announce
  315. .. _`salt-packagers`: https://groups.google.com/forum/#!forum/salt-packagers
  316. .. _`salt-slack`: https://saltstackcommunity.herokuapp.com/
  317. .. |windownload| raw:: html
  318. <p>Python3 x86: <a
  319. href="https://repo.saltstack.com/windows/Salt-Minion-{release}-Py3-x86-Setup.exe"><strong>Salt-Minion-{release}-x86-Setup.exe</strong></a>
  320. | <a href="https://repo.saltstack.com/windows/Salt-Minion-{release}-Py3-x86-Setup.exe.md5"><strong>md5</strong></a></p>
  321. <p>Python3 AMD64: <a
  322. href="https://repo.saltstack.com/windows/Salt-Minion-{release}-Py3-AMD64-Setup.exe"><strong>Salt-Minion-{release}-AMD64-Setup.exe</strong></a>
  323. | <a href="https://repo.saltstack.com/windows/Salt-Minion-{release}-Py3-AMD64-Setup.exe.md5"><strong>md5</strong></a></p>
  324. .. |osxdownloadpy3| raw:: html
  325. <p>x86_64: <a href="https://repo.saltstack.com/osx/salt-{release}-py3-x86_64.pkg"><strong>salt-{release}-py3-x86_64.pkg</strong></a>
  326. | <a href="https://repo.saltstack.com/osx/salt-{release}-py3-x86_64.pkg.md5"><strong>md5</strong></a></p>
  327. """.format(
  328. release=stripped_release
  329. )
  330. # A shortcut for linking to tickets on the GitHub issue tracker
  331. extlinks = {
  332. "blob": (
  333. "https://github.com/saltstack/salt/blob/%s/%%s" % repo_primary_branch,
  334. None,
  335. ),
  336. "issue": ("https://github.com/saltstack/salt/issues/%s", "issue #"),
  337. "pull": ("https://github.com/saltstack/salt/pull/%s", "PR #"),
  338. "formula_url": ("https://github.com/saltstack-formulas/%s", ""),
  339. }
  340. # ----- Localization -------------------------------------------------------->
  341. locale_dirs = ["locale/"]
  342. gettext_compact = False
  343. # <---- Localization ---------------------------------------------------------
  344. ### HTML options
  345. # set 'HTML_THEME=saltstack' to use previous theme
  346. html_theme = os.environ.get("HTML_THEME", "saltstack2")
  347. html_theme_path = ["_themes"]
  348. html_title = ""
  349. html_short_title = "Salt"
  350. html_static_path = ["_static"]
  351. html_logo = None # specified in the theme layout.html
  352. html_favicon = "favicon.ico"
  353. smartquotes = False
  354. # Use Google customized search or use Sphinx built-in JavaScript search
  355. if on_saltstack:
  356. html_search_template = "googlesearch.html"
  357. else:
  358. html_search_template = "searchbox.html"
  359. html_additional_pages = {
  360. "404": "404.html",
  361. }
  362. html_default_sidebars = [
  363. html_search_template,
  364. "version.html",
  365. "localtoc.html",
  366. "relations.html",
  367. "sourcelink.html",
  368. "saltstack.html",
  369. ]
  370. html_sidebars = {
  371. "ref/**/all/salt.*": [
  372. html_search_template,
  373. "version.html",
  374. "modules-sidebar.html",
  375. "localtoc.html",
  376. "relations.html",
  377. "sourcelink.html",
  378. "saltstack.html",
  379. ],
  380. "ref/formula/all/*": [],
  381. }
  382. html_context = {
  383. "on_saltstack": on_saltstack,
  384. "html_default_sidebars": html_default_sidebars,
  385. "github_base": "https://github.com/saltstack/salt",
  386. "github_issues": "https://github.com/saltstack/salt/issues",
  387. "github_downloads": "https://github.com/saltstack/salt/downloads",
  388. "latest_release": latest_release,
  389. "previous_release": previous_release,
  390. "previous_release_dir": previous_release_dir,
  391. "next_release": next_release,
  392. "next_release_dir": next_release_dir,
  393. "search_cx": search_cx,
  394. "build_type": build_type,
  395. "today": today,
  396. "copyright": copyright,
  397. "repo_primary_branch": repo_primary_branch,
  398. }
  399. html_use_index = True
  400. html_last_updated_fmt = "%b %d, %Y"
  401. html_show_sourcelink = False
  402. html_show_sphinx = True
  403. html_show_copyright = True
  404. ### Latex options
  405. latex_documents = [
  406. ("contents", "Salt.tex", "Salt Documentation", "SaltStack, Inc.", "manual"),
  407. ]
  408. latex_logo = "_static/salt-logo.png"
  409. latex_elements = {
  410. "inputenc": "", # use XeTeX instead of the inputenc LaTeX package.
  411. "utf8extra": "",
  412. "preamble": r"""
  413. \usepackage{fontspec}
  414. \setsansfont{Linux Biolinum O}
  415. \setromanfont{Linux Libertine O}
  416. \setmonofont{Source Code Pro}
  417. """,
  418. }
  419. ### Linux Biolinum, Linux Libertine: http://www.linuxlibertine.org/
  420. ### Source Code Pro: https://github.com/adobe-fonts/source-code-pro/releases
  421. ### Linkcheck options
  422. linkcheck_ignore = [
  423. r"http://127.0.0.1",
  424. r"http://salt:\d+",
  425. r"http://local:\d+",
  426. r"https://console.aws.amazon.com",
  427. r"http://192.168.33.10",
  428. r"http://domain:\d+",
  429. r"http://123.456.789.012:\d+",
  430. r"http://localhost",
  431. r"https://groups.google.com/forum/#!forum/salt-users",
  432. r"https://www.elastic.co/logstash/docs/latest/inputs/udp",
  433. r"https://www.elastic.co/logstash/docs/latest/inputs/zeromq",
  434. r"http://www.youtube.com/saltstack",
  435. r"https://raven.readthedocs.io",
  436. r"https://getsentry.com",
  437. r"https://salt-cloud.readthedocs.io",
  438. r"https://salt.readthedocs.io",
  439. r"http://www.pip-installer.org/",
  440. r"http://www.windowsazure.com/",
  441. r"https://github.com/watching",
  442. r"dash-feed://",
  443. r"https://github.com/saltstack/salt/",
  444. r"http://bootstrap.saltstack.org",
  445. r"https://bootstrap.saltstack.com",
  446. r"https://raw.githubusercontent.com/saltstack/salt-bootstrap/stable/bootstrap-salt.sh",
  447. r"media.readthedocs.org/dash/salt/latest/salt.xml",
  448. r"https://portal.aws.amazon.com/gp/aws/securityCredentials",
  449. r"https://help.github.com/articles/fork-a-repo",
  450. r"dash-feed://https%3A//media.readthedocs.org/dash/salt/latest/salt.xml",
  451. ]
  452. linkcheck_anchors = False
  453. ### Manpage options
  454. # One entry per manual page. List of tuples
  455. # (source start file, name, description, authors, manual section).
  456. authors = [
  457. "Thomas S. Hatch <thatch45@gmail.com> and many others, please see the Authors file",
  458. ]
  459. man_pages = [
  460. ("contents", "salt", "Salt Documentation", authors, 7),
  461. ("ref/cli/salt", "salt", "salt", authors, 1),
  462. ("ref/cli/salt-master", "salt-master", "salt-master Documentation", authors, 1),
  463. ("ref/cli/salt-minion", "salt-minion", "salt-minion Documentation", authors, 1),
  464. ("ref/cli/salt-key", "salt-key", "salt-key Documentation", authors, 1),
  465. ("ref/cli/salt-cp", "salt-cp", "salt-cp Documentation", authors, 1),
  466. ("ref/cli/salt-call", "salt-call", "salt-call Documentation", authors, 1),
  467. ("ref/cli/salt-proxy", "salt-proxy", "salt-proxy Documentation", authors, 1),
  468. ("ref/cli/salt-syndic", "salt-syndic", "salt-syndic Documentation", authors, 1),
  469. ("ref/cli/salt-run", "salt-run", "salt-run Documentation", authors, 1),
  470. ("ref/cli/salt-ssh", "salt-ssh", "salt-ssh Documentation", authors, 1),
  471. ("ref/cli/salt-cloud", "salt-cloud", "Salt Cloud Command", authors, 1),
  472. ("ref/cli/salt-api", "salt-api", "salt-api Command", authors, 1),
  473. ("ref/cli/salt-unity", "salt-unity", "salt-unity Command", authors, 1),
  474. ("ref/cli/spm", "spm", "Salt Package Manager Command", authors, 1),
  475. ]
  476. ### epub options
  477. epub_title = "Salt Documentation"
  478. epub_author = "SaltStack, Inc."
  479. epub_publisher = epub_author
  480. epub_copyright = copyright
  481. epub_scheme = "URL"
  482. epub_identifier = "http://saltstack.com/"
  483. epub_tocdup = False
  484. # epub_tocdepth = 3
  485. def skip_mod_init_member(app, what, name, obj, skip, options):
  486. # pylint: disable=too-many-arguments,unused-argument
  487. if name.startswith("_"):
  488. return True
  489. if isinstance(obj, types.FunctionType) and obj.__name__ == "mod_init":
  490. return True
  491. return False
  492. def _normalize_version(args):
  493. _, path = args
  494. return ".".join([x.zfill(4) for x in (path.split("/")[-1].split("."))])
  495. class ReleasesTree(TocTree):
  496. option_spec = dict(TocTree.option_spec)
  497. def run(self):
  498. rst = super().run()
  499. entries = rst[0][0]["entries"][:]
  500. entries.sort(key=_normalize_version, reverse=True)
  501. rst[0][0]["entries"][:] = entries
  502. return rst
  503. def setup(app):
  504. app.add_directive("releasestree", ReleasesTree)
  505. app.connect("autodoc-skip-member", skip_mod_init_member)