2022-10-05 21:44:23 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2023-01-20 23:34:27 +00:00
|
|
|
require 'distributed_press/v1/client/site'
|
2023-02-09 23:11:17 +00:00
|
|
|
require 'njalla/v1'
|
2023-01-20 23:34:27 +00:00
|
|
|
|
|
|
|
# Soportar Distributed Press APIv1
|
|
|
|
#
|
|
|
|
# Usa tokens de publicación efímeros para todas las acciones.
|
2022-10-05 21:44:23 +00:00
|
|
|
#
|
2023-01-20 23:34:27 +00:00
|
|
|
# Al ser creado, genera el sitio en la instancia de Distributed Press
|
|
|
|
# configurada y almacena el ID.
|
2022-10-05 21:44:23 +00:00
|
|
|
#
|
2023-01-20 23:34:27 +00:00
|
|
|
# Al ser publicado, envía los archivos en un tarball y actualiza la
|
|
|
|
# información.
|
2022-10-05 21:44:23 +00:00
|
|
|
class DeployDistributedPress < Deploy
|
2023-01-20 23:34:27 +00:00
|
|
|
store :values, accessors: %i[hostname remote_site_id remote_info], coder: JSON
|
|
|
|
|
2023-03-17 20:39:41 +00:00
|
|
|
before_create :create_remote_site!, :create_njalla_records!
|
2023-03-31 16:35:42 +00:00
|
|
|
before_destroy :delete_remote_site!, :delete_njalla_records!
|
2023-01-20 23:34:27 +00:00
|
|
|
|
2023-03-18 19:40:17 +00:00
|
|
|
DEPENDENCIES = %i[deploy_local]
|
2023-01-20 23:34:27 +00:00
|
|
|
|
|
|
|
# Actualiza la información y luego envía los cambios
|
|
|
|
#
|
|
|
|
# @param :output [Bool]
|
|
|
|
# @return [Bool]
|
2023-01-23 21:40:15 +00:00
|
|
|
def deploy(output: true)
|
2023-01-20 23:34:27 +00:00
|
|
|
status = false
|
2023-02-08 20:08:02 +00:00
|
|
|
log = []
|
|
|
|
|
|
|
|
time_start
|
2023-01-20 23:34:27 +00:00
|
|
|
|
2023-03-17 20:39:41 +00:00
|
|
|
create_remote_site! if remote_site_id.blank?
|
2023-03-27 17:10:35 +00:00
|
|
|
create_njalla_records!
|
2023-03-17 20:39:41 +00:00
|
|
|
save
|
2023-03-17 20:37:48 +00:00
|
|
|
|
2023-03-31 16:58:10 +00:00
|
|
|
if remote_site_id.blank?
|
|
|
|
raise DeployJob::DeployException, 'El sitio no se creó en Distributed Press'
|
|
|
|
end
|
|
|
|
|
2023-03-31 17:38:04 +00:00
|
|
|
if create_njalla_records? && remote_info[:njalla].blank?
|
2023-03-31 16:58:10 +00:00
|
|
|
raise DeployJob::DeployException, 'No se pudieron crear los registros necesarios en Njalla'
|
2023-03-17 20:44:13 +00:00
|
|
|
end
|
|
|
|
|
2023-01-20 23:34:27 +00:00
|
|
|
site_client.tap do |c|
|
2023-02-08 20:08:02 +00:00
|
|
|
stdout = Thread.new(publisher.logger_out) do |io|
|
|
|
|
until io.eof?
|
|
|
|
line = io.gets
|
|
|
|
|
|
|
|
puts line if output
|
|
|
|
log << line
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-01-20 23:34:27 +00:00
|
|
|
status = c.publish(publishing_site, deploy_local.destination)
|
2023-02-08 20:08:02 +00:00
|
|
|
|
2023-03-31 17:44:48 +00:00
|
|
|
if status
|
|
|
|
self.remote_info[:distributed_press] = c.show(publishing_site).to_h
|
|
|
|
save
|
|
|
|
end
|
|
|
|
|
2023-02-08 20:08:02 +00:00
|
|
|
publisher.logger.close
|
|
|
|
stdout.join
|
2023-01-20 23:34:27 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
time_stop
|
|
|
|
|
2023-02-08 20:08:02 +00:00
|
|
|
create_stat! status, log.join
|
2022-10-05 21:44:23 +00:00
|
|
|
|
2023-01-20 23:34:27 +00:00
|
|
|
status
|
|
|
|
end
|
2022-10-05 21:44:23 +00:00
|
|
|
|
|
|
|
def limit; end
|
|
|
|
|
|
|
|
def size
|
|
|
|
deploy_local.size
|
|
|
|
end
|
|
|
|
|
2023-01-20 23:34:27 +00:00
|
|
|
def destination; end
|
|
|
|
|
2023-02-08 21:49:37 +00:00
|
|
|
# Devuelve las URLs de todos los protocolos
|
|
|
|
def urls
|
2023-03-31 17:49:17 +00:00
|
|
|
protocol_urls + gateway_urls
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def gateway_urls
|
2023-03-31 17:38:04 +00:00
|
|
|
remote_info.dig(:distributed_press, :links).values.map do |protocol|
|
2023-02-08 21:49:37 +00:00
|
|
|
[ protocol[:link], protocol[:gateway] ]
|
|
|
|
end.flatten.compact.select do |link|
|
|
|
|
link.include? '://'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-03-31 17:49:17 +00:00
|
|
|
def protocol_urls
|
|
|
|
remote_info.dig(:distributed_press, :protocols).select do |_, enabled|
|
|
|
|
enabled
|
|
|
|
end.map do |protocol, _|
|
|
|
|
"#{protocol}://#{site.hostname}"
|
|
|
|
end
|
|
|
|
end
|
2023-01-20 23:34:27 +00:00
|
|
|
|
|
|
|
# El cliente de la API
|
|
|
|
#
|
|
|
|
# TODO: cuando soportemos más, tiene que haber una relación entre
|
|
|
|
# DeployDistributedPress y DistributedPressPublisher.
|
|
|
|
#
|
|
|
|
# @return [DistributedPressPublisher]
|
|
|
|
def publisher
|
2023-03-31 15:01:00 +00:00
|
|
|
@publisher ||= DistributedPressPublisher.last
|
2022-10-05 21:44:23 +00:00
|
|
|
end
|
|
|
|
|
2023-01-20 23:34:27 +00:00
|
|
|
# El cliente para actualizar el sitio
|
2022-10-05 21:44:23 +00:00
|
|
|
#
|
2023-01-20 23:34:27 +00:00
|
|
|
# @return [DistributedPress::V1::Client::Site]
|
|
|
|
def site_client
|
2023-01-23 21:39:10 +00:00
|
|
|
DistributedPress::V1::Client::Site.new(publisher.client)
|
2022-10-05 21:44:23 +00:00
|
|
|
end
|
|
|
|
|
2023-01-20 23:34:27 +00:00
|
|
|
# Genera el esquema de datos para poder publicar el sitio
|
|
|
|
#
|
|
|
|
# @return [DistributedPress::V1::Schemas::PublishingSite]
|
|
|
|
def publishing_site
|
|
|
|
DistributedPress::V1::Schemas::PublishingSite.new.call(id: remote_site_id)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Genera el esquema de datos para crear el sitio
|
|
|
|
#
|
|
|
|
# @return [DistributedPressPublisher::V1::Schemas::NewSite]
|
|
|
|
def create_site
|
|
|
|
DistributedPress::V1::Schemas::NewSite.new.call(domain: hostname, protocols: { http: true, ipfs: true, hyper: true })
|
|
|
|
end
|
|
|
|
|
|
|
|
# Crea el sitio en la instancia con el hostname especificado
|
|
|
|
#
|
|
|
|
# @return [nil]
|
|
|
|
def create_remote_site!
|
2023-01-26 18:58:22 +00:00
|
|
|
self.hostname = site.hostname
|
|
|
|
|
2023-01-20 23:34:27 +00:00
|
|
|
created_site = site_client.create(create_site)
|
|
|
|
|
|
|
|
self.remote_site_id = created_site[:id]
|
2023-03-31 17:38:04 +00:00
|
|
|
self.remote_info ||= {}
|
|
|
|
self.remote_info[:distributed_press] = created_site.to_h
|
2023-03-31 15:14:14 +00:00
|
|
|
nil
|
2023-03-20 15:13:51 +00:00
|
|
|
rescue DistributedPress::V1::Error => e
|
2023-03-17 20:39:41 +00:00
|
|
|
ExceptionNotifier.notify_exception(e, data: { site: site.name })
|
|
|
|
nil
|
|
|
|
end
|
2023-01-20 23:34:27 +00:00
|
|
|
|
2023-03-17 20:39:41 +00:00
|
|
|
# Crea los registros en Njalla
|
|
|
|
#
|
2023-03-31 16:58:10 +00:00
|
|
|
# XXX: Esto depende de nuestro DNS actual, cuando lo migremos hay
|
|
|
|
# que eliminarlo.
|
|
|
|
#
|
2023-03-17 20:39:41 +00:00
|
|
|
# @return [nil]
|
|
|
|
def create_njalla_records!
|
2023-03-31 16:58:10 +00:00
|
|
|
return unless create_njalla_records?
|
|
|
|
|
|
|
|
self.remote_info ||= {}
|
2023-03-31 17:38:04 +00:00
|
|
|
self.remote_info[:njalla] ||= {}
|
|
|
|
self.remote_info[:njalla][:a] ||= njalla.add_record(name: site.name, type: 'CNAME', content: "#{Site.domain}.").to_h
|
|
|
|
self.remote_info[:njalla][:cname] ||= njalla.add_record(name: "www.#{site.name}", type: 'CNAME', content: "#{Site.domain}.").to_h
|
|
|
|
self.remote_info[:njalla][:ns] ||= njalla.add_record(name: "_dnslink.#{site.name}", type: 'NS', content: "#{publisher.hostname}.").to_h
|
2023-03-31 16:58:10 +00:00
|
|
|
|
|
|
|
nil
|
2023-03-17 20:39:41 +00:00
|
|
|
rescue HTTParty::Error => e
|
2023-03-17 20:33:52 +00:00
|
|
|
ExceptionNotifier.notify_exception(e, data: { site: site.name })
|
2023-03-31 17:38:04 +00:00
|
|
|
self.remote_info.delete :njalla
|
2023-03-17 20:33:52 +00:00
|
|
|
ensure
|
2023-01-20 23:34:27 +00:00
|
|
|
nil
|
|
|
|
end
|
|
|
|
|
|
|
|
# Registra lo que sucedió
|
|
|
|
#
|
|
|
|
# @param status [Bool]
|
2023-02-08 20:08:02 +00:00
|
|
|
# @param log [String]
|
2023-01-20 23:34:27 +00:00
|
|
|
# @return [nil]
|
2023-02-08 20:08:02 +00:00
|
|
|
def create_stat!(status, log)
|
|
|
|
build_stats.create action: publisher.to_s,log: log, seconds: time_spent_in_seconds, bytes: size, status: status
|
2023-01-20 23:34:27 +00:00
|
|
|
nil
|
|
|
|
end
|
2023-02-09 23:01:22 +00:00
|
|
|
|
2023-03-31 15:14:14 +00:00
|
|
|
def delete_remote_site!
|
2023-03-31 16:40:50 +00:00
|
|
|
site_client.delete(publishing_site)
|
2023-03-31 15:14:14 +00:00
|
|
|
nil
|
|
|
|
rescue DistributedPress::V1::Error => e
|
|
|
|
ExceptionNotifier.notify_exception(e, data: { site: site.name })
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
|
2023-03-31 16:35:42 +00:00
|
|
|
def delete_njalla_records!
|
2023-03-31 16:58:10 +00:00
|
|
|
return unless create_njalla_records?
|
|
|
|
|
2023-03-31 16:42:23 +00:00
|
|
|
%w[a ns cname].each do |type|
|
2023-03-31 16:44:10 +00:00
|
|
|
next if (id = remote_info.dig('njalla', type, 'id')).blank?
|
2023-03-31 16:35:42 +00:00
|
|
|
|
2023-03-31 16:44:10 +00:00
|
|
|
njalla.remove_record(id: id.to_i)
|
2023-03-31 16:35:42 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-02-09 23:01:22 +00:00
|
|
|
# Actualizar registros en Njalla
|
|
|
|
#
|
|
|
|
# @return [Njalla::V1::Domain]
|
|
|
|
def njalla
|
|
|
|
@njalla ||=
|
|
|
|
begin
|
2023-03-23 20:11:51 +00:00
|
|
|
client = Njalla::V1::Client.new(token: Rails.application.credentials.njalla)
|
2023-02-09 23:01:22 +00:00
|
|
|
|
|
|
|
Njalla::V1::Domain.new(domain: Site.domain, client: client)
|
|
|
|
end
|
|
|
|
end
|
2023-03-31 16:58:10 +00:00
|
|
|
|
|
|
|
# Detecta si tenemos que crear registros en Njalla
|
|
|
|
def create_njalla_records?
|
|
|
|
!site.name.end_with?('.')
|
|
|
|
end
|
2022-10-05 21:44:23 +00:00
|
|
|
end
|