destinations.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import threading
  2. from flask import (
  3. Blueprint,
  4. current_app,
  5. flash,
  6. redirect,
  7. render_template,
  8. request,
  9. url_for,
  10. )
  11. from db import db, Destination, JobDestination
  12. bp = Blueprint("dest", __name__)
  13. @bp.route("/destinations")
  14. def destinations_list():
  15. destinations = Destination.query.order_by(Destination.name).all()
  16. return render_template("destinations.html", destinations=destinations)
  17. @bp.route("/destinations/new", methods=["GET", "POST"])
  18. def destination_new():
  19. if request.method == "POST":
  20. return _save_destination(None)
  21. return render_template("destination_form.html", dest=None)
  22. @bp.route("/destinations/<int:dest_id>/edit", methods=["GET", "POST"])
  23. def destination_edit(dest_id):
  24. dest = db.get_or_404(Destination, dest_id)
  25. if request.method == "POST":
  26. return _save_destination(dest)
  27. pub_key = _get_pub_key(dest)
  28. return render_template("destination_form.html", dest=dest, pub_key=pub_key)
  29. @bp.route("/destinations/<int:dest_id>/delete", methods=["POST"])
  30. def destination_delete(dest_id):
  31. dest = db.get_or_404(Destination, dest_id)
  32. JobDestination.query.filter_by(dest_type="ssh", dest_id=dest_id).delete()
  33. db.session.delete(dest)
  34. db.session.commit()
  35. flash(f"Destination « {dest.name} » supprimée.", "success")
  36. return redirect(url_for("cfg.settings") + "?tab=destinations")
  37. @bp.route("/destinations/<int:dest_id>/test", methods=["POST"])
  38. def destination_test(dest_id):
  39. dest = db.get_or_404(Destination, dest_id)
  40. from jobs.transfer import test_connection
  41. ok, msg = test_connection(dest, current_app.config["DATA_DIR"])
  42. flash(msg, "success" if ok else "error")
  43. return redirect(url_for("cfg.settings") + "?tab=destinations")
  44. @bp.route("/archives/<path:archive_name>/transfer", methods=["POST"])
  45. def archive_transfer(archive_name):
  46. dest_id = request.form.get("destination_id", type=int)
  47. dest = db.get_or_404(Destination, dest_id)
  48. app = current_app._get_current_object()
  49. def _do_transfer():
  50. with app.app_context():
  51. try:
  52. from jobs.transfer import transfer_archive
  53. transfer_archive(archive_name, dest, app.config["YUNOHOST_BACKUP_DIR"],
  54. app.config["DATA_DIR"])
  55. app.logger.info(f"Transfert {archive_name} → {dest.remote_str} OK")
  56. except Exception as exc:
  57. app.logger.error(f"Transfert {archive_name} échoué : {exc}")
  58. threading.Thread(target=_do_transfer, daemon=True).start()
  59. flash(f"Transfert de « {archive_name} » vers {dest.remote_str} démarré.", "success")
  60. return redirect(request.referrer or url_for("jobs.index"))
  61. def _save_destination(dest):
  62. f = request.form
  63. name = f.get("name", "").strip()
  64. host = f.get("host", "").strip()
  65. if not name or not host:
  66. flash("Nom et hôte sont requis.", "error")
  67. return render_template("destination_form.html", dest=dest)
  68. is_new = dest is None
  69. if is_new:
  70. dest = Destination()
  71. db.session.add(dest)
  72. dest.name = name
  73. dest.host = host
  74. dest.port = int(f.get("port", 22) or 22)
  75. dest.user = f.get("user", "root").strip() or "root"
  76. dest.remote_path = f.get("remote_path", "/home/yunohost.backup/archives").strip()
  77. dest.enabled = f.get("enabled") == "1"
  78. db.session.flush()
  79. if not dest.key_name:
  80. from jobs.transfer import generate_key
  81. dest.key_name = generate_key(dest.name, current_app.config["DATA_DIR"])
  82. db.session.commit()
  83. flash(f"Destination « {dest.name} » enregistrée.", "success")
  84. return redirect(url_for("dest.destination_edit", dest_id=dest.id))
  85. def _get_pub_key(dest):
  86. if not dest.key_name:
  87. return None
  88. from jobs.transfer import get_public_key
  89. return get_public_key(dest.key_name, current_app.config["DATA_DIR"])