Mantener los hostnames anteriores a medida que se cambia de nombre

Para no romper links preexistentes.  Lo ideal sería que todos los Deploy
se vinculen al directorio principal para no romper links, pero la idea
es no romperlos (?)
This commit is contained in:
f 2021-08-14 20:21:30 -03:00
parent e6ea1001cd
commit 341a693a35
7 changed files with 111 additions and 16 deletions

View file

@ -5,20 +5,27 @@ require 'open3'
# Este modelo implementa los distintos tipos de alojamiento que provee
# Sutty.
#
# Cuando cambia el hostname de un Deploy, generamos un
# DeployAlternativeDomain en su lugar. Esto permite que no se rompan
# links preexistentes y que el nombre no pueda ser tomado por alguien
# más.
#
# TODO: Cambiar el nombre a algo que no sea industrial/militar.
class Deploy < ApplicationRecord
# Un sitio puede tener muchas formas de publicarse.
belongs_to :site
# Puede tener muchos access logs a través del hostname
has_many :access_logs, primary_key: 'hostname', foreign_key: 'host'
# Registro de las tareas ejecutadas
has_many :build_stats, dependent: :destroy
# Siempre generar el hostname
after_initialize :default_hostname!
# Eliminar los archivos generados por el deploy.
before_destroy :remove_destination!
# Registro de las tareas ejecutadas
has_many :build_stats, dependent: :destroy
# Los hostnames alternativos se crean después de actualizar, cuando ya
# se modificó el hostname.
around_update :create_alternative_domain!, if: :destination_changed?
# Siempre tienen que pertenecer a un sitio
validates :site, presence: true
@ -34,6 +41,37 @@ class Deploy < ApplicationRecord
where(hostname: hostname).includes(:site).pluck(:name).first
end
# Detecta si el destino existe y si no es un symlink roto.
def exist?
File.exist? destination
end
# Detecta si el link está roto
def broken?
File.symlink?(destination) && !File.exist?(File.readlink(destination))
end
# Ubicación del deploy
#
# @return [String] Una ruta en el sistema de archivos
def destination
File.join(Rails.root, '_deploy', hostname)
end
# Ubicación anterior del deploy
#
# @return [String] Una ruta en el sistema de archivos
def destination_was
return destination unless will_save_change_to_hostname?
File.join(Rails.root, '_deploy', hostname_was)
end
# Determina si la ubicación cambió
def destination_changed?
persisted? && will_save_change_to_hostname?
end
# Genera el hostname
#
# @return [String]
@ -143,6 +181,20 @@ class Deploy < ApplicationRecord
raise NotImplementedError
end
# Cuando el deploy cambia de hostname, generamos un dominio
# alternativo para no romper links hacia este sitio.
def create_alternative_domain!
hw = hostname_was
# Aplicar la actualización
yield
# Crear el deploy alternativo con el nombre anterior una vez que
# lo cambiamos en la base de datos.
ad = site.deploys.create(type: 'DeployAlternativeDomain', hostname: hw)
ad.deploy if ad.persisted?
end
# Convierte el comando en una versión resumida.
#
# @param [String]

View file

@ -37,6 +37,11 @@ class DeployHiddenService < DeployWww
private
# No soportamos cambiar de onion
def destination_changed?
false
end
def implements_hostname_validation?
true
end

View file

@ -3,7 +3,7 @@
# Alojamiento local, genera el sitio como si corriéramos `jekyll build`.
class DeployLocal < Deploy
# Asegurarse que el hostname es el permitido.
before_save :reset_hostname!, :default_hostname!
before_validation :reset_hostname!, :default_hostname!
# Realizamos la construcción del sitio usando Jekyll y un entorno
# limpio para no pasarle secretos
@ -30,13 +30,6 @@ class DeployLocal < Deploy
end.inject(:+)
end
# La ubicación del sitio luego de generarlo.
#
# @return [String]
def destination
File.join(Rails.root, '_deploy', hostname)
end
# El hostname es el nombre del sitio más el dominio principal.
#
# @return [String]

View file

@ -20,11 +20,6 @@ class DeployWww < Deploy
File.size destination
end
# @return [String]
def destination
File.join(Rails.root, '_deploy', hostname)
end
# El hostname por defecto incluye WWW
#
# @return [String]

View file

@ -143,6 +143,10 @@ en:
tienda_api_key: Store access key
errors:
models:
deploy:
attributes:
hostname:
destination_exist: 'There already is a file in the destination'
site:
attributes:
name:

View file

@ -143,6 +143,10 @@ es:
tienda_api_key: Clave de acceso
errors:
models:
deploy:
attributes:
hostname:
destination_exist: 'Ya hay un archivo en esta ubicación'
site:
attributes:
name:

View file

@ -22,4 +22,46 @@ class Site::DeploymentTest < ActiveSupport::TestCase
assert site_pre.deploys.create(type: 'DeployAlternativeDomain', hostname: "#{dup_name}.#{Site.domain}")
assert_not site.update(name: dup_name)
end
test 'al cambiar el nombre se crea un deploy alternativo' do
site_name = site.name
new_name = SecureRandom.hex
original_destination = site.deploy_local.destination
urls = [site.url]
assert site.deploy_local.deploy
assert_not site.deploy_local.destination_changed?
assert site.update(name: new_name)
urls << site.url
assert_equal urls.sort, site.urls.sort
assert File.symlink?(original_destination)
assert File.exist?(site.deploy_local.destination)
assert_equal 2, site.deploys.count
end
test 'al cambiar el nombre se renombra el directorio' do
site_name = site.name
new_name = "test-#{SecureRandom.hex}"
original_destination = site.deploy_local.destination
assert site.deploy_local.deploy
assert_not site.deploy_local.destination_changed?
assert site.update(name: new_name)
assert site.deploy_local.hostname.start_with?(new_name)
assert File.symlink?(original_destination)
assert File.exist?(site.deploy_local.destination)
end
test 'al cambiar el nombre varias veces se crean varios links' do
assert site.deploy_local.deploy
q = rand(3..10)
q.times do
assert site.update(name: "test-#{SecureRandom.hex}")
end
assert_equal q, site.deploys.count
end
end