You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

448 lines
12 KiB

  1. # imports - standard imports
  2. import os
  3. import sys
  4. # imports - third party imports
  5. import click
  6. # imports - module imports
  7. from bench.utils import exec_cmd, run_playbook, which
  8. from bench.utils.cli import SugaredOption
  9. @click.group(help="Setup command group for enabling setting up a Xhiveframework environment")
  10. def setup():
  11. pass
  12. @click.command(
  13. "sudoers", help="Add commands to sudoers list for execution without password"
  14. )
  15. @click.argument("user")
  16. def setup_sudoers(user):
  17. from bench.utils.system import setup_sudoers
  18. setup_sudoers(user)
  19. @click.command("nginx", help="Generate configuration files for NGINX")
  20. @click.option(
  21. "--logging", default="combined", type=click.Choice(["none", "site", "combined"])
  22. )
  23. @click.option(
  24. "--log_format",
  25. help="Specify the log_format for nginx. Use none or '' to not set a value.",
  26. only_if_set=["logging"],
  27. cls=SugaredOption,
  28. default="main",
  29. )
  30. @click.option(
  31. "--yes", help="Yes to regeneration of nginx config file", default=False, is_flag=True
  32. )
  33. def setup_nginx(yes=False, logging="combined", log_format=None):
  34. from bench.config.nginx import make_nginx_conf
  35. make_nginx_conf(bench_path=".", yes=yes, logging=logging, log_format=log_format)
  36. @click.command("reload-nginx", help="Checks NGINX config file and reloads service")
  37. def reload_nginx():
  38. from bench.config.production_setup import reload_nginx
  39. reload_nginx()
  40. @click.command("supervisor", help="Generate configuration for supervisor")
  41. @click.option("--user", help="optional user argument")
  42. @click.option(
  43. "--yes", help="Yes to regeneration of supervisor config", is_flag=True, default=False
  44. )
  45. @click.option(
  46. "--skip-redis", help="Skip redis configuration", is_flag=True, default=False
  47. )
  48. @click.option(
  49. "--skip-supervisord",
  50. help="Skip supervisord configuration",
  51. is_flag=True,
  52. default=False,
  53. )
  54. def setup_supervisor(user=None, yes=False, skip_redis=False, skip_supervisord=False):
  55. from bench.utils import get_cmd_output
  56. from bench.config.supervisor import (
  57. check_supervisord_config,
  58. generate_supervisor_config,
  59. )
  60. if which("supervisorctl") is None:
  61. click.secho("Please install `supervisor` to proceed", fg="red")
  62. sys.exit(1)
  63. if not skip_supervisord and "Permission denied" in get_cmd_output(
  64. "supervisorctl status"
  65. ):
  66. check_supervisord_config(user=user)
  67. generate_supervisor_config(bench_path=".", user=user, yes=yes, skip_redis=skip_redis)
  68. @click.command("redis", help="Generates configuration for Redis")
  69. def setup_redis():
  70. from bench.config.redis import generate_config
  71. generate_config(".")
  72. @click.command("fonts", help="Add Xhiveframework fonts to system")
  73. def setup_fonts():
  74. from bench.utils.system import setup_fonts
  75. setup_fonts()
  76. @click.command(
  77. "production", help="Setup Xhiveframework production environment for specific user"
  78. )
  79. @click.argument("user")
  80. @click.option("--yes", help="Yes to regeneration config", is_flag=True, default=False)
  81. def setup_production(user, yes=False):
  82. from bench.config.production_setup import setup_production
  83. setup_production(user=user, yes=yes)
  84. @click.command("backups", help="Add cronjob for bench backups")
  85. def setup_backups():
  86. from bench.bench import Bench
  87. Bench(".").setup.backups()
  88. @click.command("env", help="Setup Python environment for bench")
  89. @click.option(
  90. "--python", type=str, default="python3", help="Path to Python Executable."
  91. )
  92. def setup_env(python="python3"):
  93. from bench.bench import Bench
  94. return Bench(".").setup.env(python=python)
  95. @click.command("firewall", help="Setup firewall for system")
  96. @click.option("--ssh_port")
  97. @click.option("--force")
  98. def setup_firewall(ssh_port=None, force=False):
  99. if not force:
  100. click.confirm(
  101. f"Setting up the firewall will block all ports except 80, 443 and {ssh_port}\nDo you want to continue?",
  102. abort=True,
  103. )
  104. if not ssh_port:
  105. ssh_port = 22
  106. run_playbook("roles/bench/tasks/setup_firewall.yml", {"ssh_port": ssh_port})
  107. @click.command("ssh-port", help="Set SSH Port for system")
  108. @click.argument("port")
  109. @click.option("--force")
  110. def set_ssh_port(port, force=False):
  111. if not force:
  112. click.confirm(
  113. f"This will change your SSH Port to {port}\nDo you want to continue?", abort=True
  114. )
  115. run_playbook("roles/bench/tasks/change_ssh_port.yml", {"ssh_port": port})
  116. @click.command("lets-encrypt", help="Setup lets-encrypt SSL for site")
  117. @click.argument("site")
  118. @click.option("--custom-domain")
  119. @click.option(
  120. "-n",
  121. "--non-interactive",
  122. default=False,
  123. is_flag=True,
  124. help="Run command non-interactively. This flag restarts nginx and runs certbot non interactively. Shouldn't be used on 1'st attempt",
  125. )
  126. def setup_letsencrypt(site, custom_domain, non_interactive):
  127. from bench.config.lets_encrypt import setup_letsencrypt
  128. setup_letsencrypt(site, custom_domain, bench_path=".", interactive=not non_interactive)
  129. @click.command(
  130. "wildcard-ssl", help="Setup wildcard SSL certificate for multi-tenant bench"
  131. )
  132. @click.argument("domain")
  133. @click.option("--email")
  134. @click.option(
  135. "--exclude-base-domain",
  136. default=False,
  137. is_flag=True,
  138. help="SSL Certificate not applicable for base domain",
  139. )
  140. def setup_wildcard_ssl(domain, email, exclude_base_domain):
  141. from bench.config.lets_encrypt import setup_wildcard_ssl
  142. setup_wildcard_ssl(
  143. domain, email, bench_path=".", exclude_base_domain=exclude_base_domain
  144. )
  145. @click.command("procfile", help="Generate Procfile for bench start")
  146. def setup_procfile():
  147. from bench.config.procfile import setup_procfile
  148. setup_procfile(".")
  149. @click.command(
  150. "socketio", help="[DEPRECATED] Setup node dependencies for socketio server"
  151. )
  152. def setup_socketio():
  153. return
  154. @click.command("requirements")
  155. @click.option("--node", help="Update only Node packages", default=False, is_flag=True)
  156. @click.option(
  157. "--python", help="Update only Python packages", default=False, is_flag=True
  158. )
  159. @click.option(
  160. "--dev",
  161. help="Install optional python development dependencies",
  162. default=False,
  163. is_flag=True,
  164. )
  165. @click.argument("apps", nargs=-1)
  166. def setup_requirements(node=False, python=False, dev=False, apps=None):
  167. """
  168. Setup Python and Node dependencies.
  169. You can optionally specify one or more apps to setup dependencies for.
  170. """
  171. from bench.bench import Bench
  172. bench = Bench(".")
  173. if not (node or python or dev):
  174. bench.setup.requirements(apps=apps)
  175. elif not node and not dev:
  176. bench.setup.python(apps=apps)
  177. elif not python and not dev:
  178. bench.setup.node(apps=apps)
  179. else:
  180. from bench.utils.bench import install_python_dev_dependencies
  181. install_python_dev_dependencies(apps=apps)
  182. if node:
  183. click.secho(
  184. "--dev flag only supports python dependencies. All node development dependencies are installed by default.",
  185. fg="yellow",
  186. )
  187. @click.command(
  188. "manager",
  189. help="Setup bench-manager.local site with the bench_manager app installed on it",
  190. )
  191. @click.option(
  192. "--yes", help="Yes to regeneration of nginx config file", default=False, is_flag=True
  193. )
  194. @click.option(
  195. "--port", help="Port on which you want to run bench manager", default=23624
  196. )
  197. @click.option("--domain", help="Domain on which you want to run bench manager")
  198. def setup_manager(yes=False, port=23624, domain=None):
  199. from bench.bench import Bench
  200. from bench.config.nginx import make_bench_manager_nginx_conf
  201. create_new_site = True
  202. if "bench-manager.local" in os.listdir("sites"):
  203. create_new_site = click.confirm("Site already exists. Overwrite existing site?")
  204. if create_new_site:
  205. exec_cmd("bench new-site --force bench-manager.local")
  206. if "bench_manager" in os.listdir("apps"):
  207. print("App already exists. Skipping app download.")
  208. else:
  209. exec_cmd("bench get-app bench_manager")
  210. exec_cmd("bench --site bench-manager.local install-app bench_manager")
  211. bench_path = "."
  212. bench = Bench(bench_path)
  213. if bench.conf.get("restart_supervisor_on_update") or bench.conf.get(
  214. "restart_systemd_on_update"
  215. ):
  216. # implicates a production setup or so I presume
  217. if not domain:
  218. print(
  219. "Please specify the site name on which you want to host bench-manager using the 'domain' flag"
  220. )
  221. sys.exit(1)
  222. if domain not in bench.sites:
  223. raise Exception("No such site")
  224. make_bench_manager_nginx_conf(bench_path, yes=yes, port=port, domain=domain)
  225. @click.command("config", help="Generate or over-write sites/common_site_config.json")
  226. def setup_config():
  227. from bench.config.common_site_config import setup_config
  228. setup_config(".")
  229. @click.command("add-domain", help="Add a custom domain to a particular site")
  230. @click.argument("domain")
  231. @click.option("--site", prompt=True)
  232. @click.option("--ssl-certificate", help="Absolute path to SSL Certificate")
  233. @click.option("--ssl-certificate-key", help="Absolute path to SSL Certificate Key")
  234. def add_domain(domain, site=None, ssl_certificate=None, ssl_certificate_key=None):
  235. """Add custom domain to site"""
  236. if not site:
  237. print("Please specify site")
  238. sys.exit(1)
  239. from bench.config.site_config import add_domain
  240. add_domain(site, domain, ssl_certificate, ssl_certificate_key, bench_path=".")
  241. @click.command("remove-domain", help="Remove custom domain from a site")
  242. @click.argument("domain")
  243. @click.option("--site", prompt=True)
  244. def remove_domain(domain, site=None):
  245. if not site:
  246. print("Please specify site")
  247. sys.exit(1)
  248. from bench.config.site_config import remove_domain
  249. remove_domain(site, domain, bench_path=".")
  250. @click.command(
  251. "sync-domains",
  252. help="Check if there is a change in domains. If yes, updates the domains list.",
  253. )
  254. @click.option("--domain", multiple=True)
  255. @click.option("--site", prompt=True)
  256. def sync_domains(domain=None, site=None):
  257. if not site:
  258. print("Please specify site")
  259. sys.exit(1)
  260. try:
  261. domains = list(map(str, domain))
  262. except Exception:
  263. print("Domains should be a json list of strings or dictionaries")
  264. sys.exit(1)
  265. from bench.config.site_config import sync_domains
  266. changed = sync_domains(site, domains, bench_path=".")
  267. # if changed, success, else failure
  268. sys.exit(0 if changed else 1)
  269. @click.command("role", help="Install dependencies via ansible roles")
  270. @click.argument("role")
  271. @click.option("--admin_emails", default="")
  272. @click.option("--mysql_root_password", "--mariadb_root_password")
  273. @click.option("--container", is_flag=True, default=False)
  274. def setup_roles(role, **kwargs):
  275. extra_vars = {"production": True}
  276. extra_vars.update(kwargs)
  277. if role:
  278. run_playbook("site.yml", extra_vars=extra_vars, tag=role)
  279. else:
  280. run_playbook("site.yml", extra_vars=extra_vars)
  281. @click.command(
  282. "fail2ban",
  283. help="Setup fail2ban, an intrusion prevention software framework that protects computer servers from brute-force attacks",
  284. )
  285. @click.option(
  286. "--maxretry",
  287. default=6,
  288. help="Number of matches (i.e. value of the counter) which triggers ban action on the IP. Default is 6 seconds",
  289. )
  290. @click.option(
  291. "--bantime",
  292. default=600,
  293. help="Duration (in seconds) for IP to be banned for. Negative number for 'permanent' ban. Default is 600 seconds",
  294. )
  295. @click.option(
  296. "--findtime",
  297. default=600,
  298. help="The counter is set to zero if match found within 'findtime' seconds doesn't exceed 'maxretry'. Default is 600 seconds",
  299. )
  300. def setup_nginx_proxy_jail(**kwargs):
  301. run_playbook("roles/fail2ban/tasks/configure_nginx_jail.yml", extra_vars=kwargs)
  302. @click.command("systemd", help="Generate configuration for systemd")
  303. @click.option("--user", help="Optional user argument")
  304. @click.option(
  305. "--yes",
  306. help="Yes to regeneration of systemd config files",
  307. is_flag=True,
  308. default=False,
  309. )
  310. @click.option("--stop", help="Stop bench services", is_flag=True, default=False)
  311. @click.option("--create-symlinks", help="Create Symlinks", is_flag=True, default=False)
  312. @click.option("--delete-symlinks", help="Delete Symlinks", is_flag=True, default=False)
  313. def setup_systemd(
  314. user=None, yes=False, stop=False, create_symlinks=False, delete_symlinks=False
  315. ):
  316. from bench.config.systemd import generate_systemd_config
  317. generate_systemd_config(
  318. bench_path=".",
  319. user=user,
  320. yes=yes,
  321. stop=stop,
  322. create_symlinks=create_symlinks,
  323. delete_symlinks=delete_symlinks,
  324. )
  325. setup.add_command(setup_sudoers)
  326. setup.add_command(setup_nginx)
  327. setup.add_command(reload_nginx)
  328. setup.add_command(setup_supervisor)
  329. setup.add_command(setup_redis)
  330. setup.add_command(setup_letsencrypt)
  331. setup.add_command(setup_wildcard_ssl)
  332. setup.add_command(setup_production)
  333. setup.add_command(setup_backups)
  334. setup.add_command(setup_env)
  335. setup.add_command(setup_procfile)
  336. setup.add_command(setup_socketio)
  337. setup.add_command(setup_requirements)
  338. setup.add_command(setup_manager)
  339. setup.add_command(setup_config)
  340. setup.add_command(setup_fonts)
  341. setup.add_command(add_domain)
  342. setup.add_command(remove_domain)
  343. setup.add_command(sync_domains)
  344. setup.add_command(setup_firewall)
  345. setup.add_command(set_ssh_port)
  346. setup.add_command(setup_roles)
  347. setup.add_command(setup_nginx_proxy_jail)
  348. setup.add_command(setup_systemd)