mirror of
https://0xacab.org/sutty/sutty
synced 2025-01-19 14:03:39 +00:00
Merge branch 'deploy-rsync' into 'rails'
hacer deploys remotos See merge request sutty/sutty!85
This commit is contained in:
commit
cf4c719cdb
8 changed files with 147 additions and 8 deletions
|
@ -28,15 +28,17 @@ class DeployLocal < Deploy
|
||||||
# Obtener el tamaño de todos los archivos y directorios (los
|
# Obtener el tamaño de todos los archivos y directorios (los
|
||||||
# directorios son archivos :)
|
# directorios son archivos :)
|
||||||
def size
|
def size
|
||||||
paths = [destination, File.join(destination, '**', '**')]
|
@size ||= begin
|
||||||
|
paths = [destination, File.join(destination, '**', '**')]
|
||||||
|
|
||||||
Dir.glob(paths).map do |file|
|
Dir.glob(paths).map do |file|
|
||||||
if File.symlink? file
|
if File.symlink? file
|
||||||
0
|
0
|
||||||
else
|
else
|
||||||
File.size(file)
|
File.size(file)
|
||||||
end
|
end
|
||||||
end.inject(:+)
|
end.inject(:+)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def destination
|
def destination
|
||||||
|
|
100
app/models/deploy_rsync.rb
Normal file
100
app/models/deploy_rsync.rb
Normal 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
|
|
@ -9,6 +9,7 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do
|
||||||
self.site = Site.new params
|
self.site = Site.new params
|
||||||
|
|
||||||
add_role temporal: false, rol: 'usuarie'
|
add_role temporal: false, rol: 'usuarie'
|
||||||
|
sync_nodes
|
||||||
|
|
||||||
I18n.with_locale(usuarie&.lang&.to_sym || I18n.default_locale) do
|
I18n.with_locale(usuarie&.lang&.to_sym || I18n.default_locale) do
|
||||||
site.save &&
|
site.save &&
|
||||||
|
@ -144,4 +145,11 @@ SiteService = Struct.new(:site, :usuarie, :params, keyword_init: true) do
|
||||||
PostService.new(site: site, usuarie: usuarie, post: post,
|
PostService.new(site: site, usuarie: usuarie, post: post,
|
||||||
params: params).update
|
params: params).update
|
||||||
end
|
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
|
end
|
||||||
|
|
1
app/views/deploys/_deploy_rsync.haml
Normal file
1
app/views/deploys/_deploy_rsync.haml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
-# nada
|
|
@ -55,5 +55,9 @@ module Sutty
|
||||||
EmailAddress::Config.error_messages translations.transform_keys(&:to_s), locale.to_s
|
EmailAddress::Config.error_messages translations.transform_keys(&:to_s), locale.to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def nodes
|
||||||
|
@nodes ||= ENV.fetch('SUTTY_NODES', '').split(',')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -102,6 +102,10 @@ en:
|
||||||
title: Alternative domain name
|
title: Alternative domain name
|
||||||
success: Success!
|
success: Success!
|
||||||
error: Error
|
error: Error
|
||||||
|
deploy_rsync:
|
||||||
|
title: Synchronize to backup server
|
||||||
|
success: Success!
|
||||||
|
error: Error
|
||||||
help: You can contact us by replying to this e-mail
|
help: You can contact us by replying to this e-mail
|
||||||
maintenance_mailer:
|
maintenance_mailer:
|
||||||
notice:
|
notice:
|
||||||
|
|
|
@ -102,6 +102,10 @@ es:
|
||||||
title: Dominio alternativo
|
title: Dominio alternativo
|
||||||
success: ¡Éxito!
|
success: ¡Éxito!
|
||||||
error: Hubo un error
|
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.
|
help: Por cualquier duda, responde este correo para contactarte con nosotres.
|
||||||
maintenance_mailer:
|
maintenance_mailer:
|
||||||
notice:
|
notice:
|
||||||
|
|
16
db/migrate/20220406211042_add_deploy_rsync_to_sites.rb
Normal file
16
db/migrate/20220406211042_add_deploy_rsync_to_sites.rb
Normal 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
|
Loading…
Reference in a new issue