From accb559f014ccc287ffcc5e6f15ce5ddae918a53 Mon Sep 17 00:00:00 2001 From: f Date: Wed, 6 Apr 2022 16:39:56 -0300 Subject: [PATCH] hacer deploys remotos --- app/models/deploy_rsync.rb | 88 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 app/models/deploy_rsync.rb diff --git a/app/models/deploy_rsync.rb b/app/models/deploy_rsync.rb new file mode 100644 index 00000000..40018dbd --- /dev/null +++ b/app/models/deploy_rsync.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +# Sincroniza sitios a servidores remotos usando Rsync. El servidor +# remoto tiene que tener rsync instalado. +class DeployRsync < Deploy + store :values, accessors: %i[flags destination host_keys], coder: JSON + + def deploy + ssh? && rsync + end + + # No se ocupa espacio local + # + # @return [Integer] + def size + 0 + end + + private + + # Verificar la conexión SSH implementando Trust On First Use + # + # TODO: Medir el tiempo que tarda en iniciarse la conexión + # + # @return [Boolean] + def ssh? + user, host = user_host + ssh_available = false + + Net::SSH.start(host, user, verify_host_key: tofu) do |ssh| + if values[:host_keys].blank? + # Guardar las llaves que se encontraron en la primera conexión + values[:host_keys] = ssh.transport.host_keys.map do |host_key| + "#{host_key.ssh_type} #{host_key.fingerprint}" + end + + ssh_available = save + else + ssh_available = true + end + end + + ssh_available + rescue Exception => e + ExceptionNotifier.notify_exception(e, data: { site: site.id, hostname: host, user: user }) + + false + end + + # Confiar en la primera llave que encontremos, fallar si cambian + # + # @return [Symbol] + def tofu + values[:host_keys].present? ? :always : :accept_new + end + + # Devuelve el par user host + # + # @return [Array] + def user_host + destination.split(':', 2).first.split('@', 2).tap do |d| + next unless d.size == 1 + + d.insert(0, nil) + end + end + + # Sincroniza hacia el directorio remoto, usando las flags opcionales. + # + # @return [Boolean] + def rsync + run %(rsync -av #{flags ? Shellwords.escape(flags) : ''} #{Shellwords.escape source}/ #{Shellwords.escape destination}/) + end + + # El origen es el destino de la compilación + # + # @return [String] + def source + site.deploys.find_by(type: 'DeployLocal').destination + end + + # Devolver el destino o lanzar un error si no está configurado + def destination + values[:destination].tap do |_d| + raise ArgumentError, 'destination no está configurado' + end + end +end