5
0
Fork 0
mirror of https://0xacab.org/sutty/sutty synced 2024-11-15 14:41:41 +00:00

Merge branch 'deploy-rsync' into 'rails'

hacer deploys remotos

See merge request sutty/sutty!85
This commit is contained in:
fauno 2022-12-28 19:23:13 +00:00
commit cf4c719cdb
8 changed files with 147 additions and 8 deletions

View file

@ -28,15 +28,17 @@ class DeployLocal < Deploy
# Obtener el tamaño de todos los archivos y directorios (los
# directorios son archivos :)
def size
paths = [destination, File.join(destination, '**', '**')]
@size ||= begin
paths = [destination, File.join(destination, '**', '**')]
Dir.glob(paths).map do |file|
if File.symlink? file
0
else
File.size(file)
end
end.inject(:+)
Dir.glob(paths).map do |file|
if File.symlink? file
0
else
File.size(file)
end
end.inject(:+)
end
end
def destination

100
app/models/deploy_rsync.rb Normal file
View file

@ -0,0 +1,100 @@
# 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[destination host_keys], coder: JSON
def deploy
ssh? && rsync
end
# El espacio remoto es el mismo que el local
#
# @return [Integer]
def size
deploy_local.size
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') if d.blank?
end
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, timeout: 5) 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
def env
{
'HOME' => home_dir,
'PATH' => '/usr/bin',
'LANG' => ENV['LANG']
}
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
#
# @return [Boolean]
def rsync
run %(rsync -aviH --timeout=5 #{Shellwords.escape source}/ #{Shellwords.escape destination}/)
end
# El origen es el destino de la compilación
#
# @return [String]
def source
deploy_local.destination
end
def deploy_local
@deploy_local ||= site.deploys.find_by(type: 'DeployLocal')
end
end

View file

@ -9,6 +9,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do
self.site = Site.new params
add_role temporal: false, rol: 'usuarie'
sync_nodes
I18n.with_locale(usuarie&.lang&.to_sym || I18n.default_locale) do
site.save &&
@ -144,4 +145,11 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do
PostService.new(site: site, usuarie: usuarie, post: post,
params: params).update
end
# Crea los deploys necesarios para sincronizar a otros nodos de Sutty
def sync_nodes
Rails.application.nodes.each do |node|
site.deploys.build(type: 'DeployRsync', destination: "sutty@#{node}:#{site.hostname}")
end
end
end

View file

@ -0,0 +1 @@
-# nada

View file

@ -55,5 +55,9 @@ module Sutty
EmailAddress::Config.error_messages translations.transform_keys(&:to_s), locale.to_s
end
end
def nodes
@nodes ||= ENV.fetch('SUTTY_NODES', '').split(',')
end
end
end

View file

@ -102,6 +102,10 @@ en:
title: Alternative domain name
success: Success!
error: Error
deploy_rsync:
title: Synchronize to backup server
success: Success!
error: Error
help: You can contact us by replying to this e-mail
maintenance_mailer:
notice:

View file

@ -102,6 +102,10 @@ es:
title: Dominio alternativo
success: ¡Éxito!
error: Hubo un error
deploy_rsync:
title: Sincronizar al servidor alternativo
success: ¡Éxito!
error: Hubo un error
help: Por cualquier duda, responde este correo para contactarte con nosotres.
maintenance_mailer:
notice:

View file

@ -0,0 +1,16 @@
# frozen_string_literal: true
# Agrega un DeployRsync hacia los servidores alternativos para cada
# sitio
class AddDeployRsyncToSites < ActiveRecord::Migration[6.1]
def up
Site.find_each do |site|
SiteService.new(site: site).send :sync_nodes
site.save
end
end
def down
DeployRsync.destroy_all
end
end