saltsh.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. '''\
  4. Welcome to the Salt repl which exposes the execution environment of a minion in
  5. a pre-configured Python shell
  6. __opts__, __salt__, __grains__, and __pillar__ are available.
  7. Jinja can be tested with full access to the above structures in the usual way:
  8. JINJA("""\\
  9. I am {{ salt['cmd.run']('whoami') }}.
  10. {% if otherstuff %}
  11. Some other stuff here
  12. {% endif %}
  13. """, otherstuff=True)
  14. A history file is maintained in ~/.saltsh_history.
  15. completion behavior can be customized via the ~/.inputrc file.
  16. '''
  17. # pylint: disable=file-perms
  18. # Import python libs
  19. from __future__ import absolute_import
  20. import atexit
  21. import os
  22. import pprint # pylint: disable=unused-import
  23. import readline
  24. import sys
  25. from code import InteractiveConsole
  26. # Import 3rd party libs
  27. import jinja2
  28. # Import salt libs
  29. import salt.client
  30. import salt.config
  31. import salt.loader
  32. import salt.output
  33. import salt.pillar
  34. import salt.runner
  35. # pylint: disable=unused-import
  36. # These are imported to be available in the spawned shell
  37. import salt.utils.yaml
  38. from salt.ext.six.moves import builtins # pylint: disable=import-error
  39. # pylint: enable=unused-import
  40. HISTFILE = "{HOME}/.saltsh_history".format(**os.environ)
  41. def savehist():
  42. """
  43. Save the history file
  44. """
  45. readline.write_history_file(HISTFILE)
  46. def get_salt_vars():
  47. """
  48. Return all the Salt-usual double-under data structures for a minion
  49. """
  50. # Create the Salt __opts__ variable
  51. __opts__ = salt.config.client_config(
  52. os.environ.get("SALT_MINION_CONFIG", "/etc/salt/minion")
  53. )
  54. # Populate grains if it hasn't been done already
  55. if "grains" not in __opts__ or not __opts__["grains"]:
  56. __opts__["grains"] = salt.loader.grains(__opts__)
  57. # file_roots and pillar_roots should be set in the minion config
  58. if "file_client" not in __opts__ or not __opts__["file_client"]:
  59. __opts__["file_client"] = "local"
  60. # ensure we have a minion id
  61. if "id" not in __opts__ or not __opts__["id"]:
  62. __opts__["id"] = "saltsh_mid"
  63. # Populate template variables
  64. __salt__ = salt.loader.minion_mods(__opts__)
  65. __grains__ = __opts__["grains"]
  66. if __opts__["file_client"] == "local":
  67. __pillar__ = salt.pillar.get_pillar(
  68. __opts__, __grains__, __opts__.get("id"), __opts__.get("saltenv"),
  69. ).compile_pillar()
  70. else:
  71. __pillar__ = {}
  72. # pylint: disable=invalid-name,unused-variable,possibly-unused-variable
  73. JINJA = lambda x, **y: jinja2.Template(x).render(
  74. grains=__grains__, salt=__salt__, opts=__opts__, pillar=__pillar__, **y
  75. )
  76. # pylint: enable=invalid-name,unused-variable,possibly-unused-variable
  77. return locals()
  78. def main():
  79. """
  80. The main entry point
  81. """
  82. salt_vars = get_salt_vars()
  83. def salt_outputter(value):
  84. """
  85. Use Salt's outputters to print values to the shell
  86. """
  87. if value is not None:
  88. builtins._ = value
  89. salt.output.display_output(value, "", salt_vars["__opts__"])
  90. sys.displayhook = salt_outputter
  91. # Set maximum number of items that will be written to the history file
  92. readline.set_history_length(300)
  93. if os.path.exists(HISTFILE):
  94. readline.read_history_file(HISTFILE)
  95. atexit.register(savehist)
  96. atexit.register(lambda: sys.stdout.write("Salt you later!\n"))
  97. saltrepl = InteractiveConsole(locals=salt_vars)
  98. saltrepl.interact(banner=__doc__)
  99. if __name__ == "__main__":
  100. main()