Como puxar imagens de um bucket que não é meu

Tenho um site com várias imagens em um bucket CDCK. Tenho pouco tempo para retirá-las desse bucket e movê-las para o servidor local (e depois para outro bucket).

As tarefas rake uploads:analyze_missing_s3 e uploads:fix_missing_s3 não encontram problemas, embora cerca de 25 mil imagens estejam em um bucket distante.

Sugestão de Recurso: Parece que EnsureS3UploadsExistence deveria marcar uploads como invalid_etag para uploads que não estão no bucket correto (ou seja, não têm permissões para esse bucket?), mas não o faz. Acho que faria sentido que este ou algum outro trabalho notasse se os uploads estavam em um bucket sobre o qual o site atual não tem controle, ou talvez apenas não seja o bucket esperado para o site.

Não consigo entender bem o que é verification_status, pois não parece verificar se é algo bom.

O que tentei

ups=Upload.where("url like '//discourse-cloud-file-uploads.s3.dualstack.us-west-2.amazonaws.com/business6%'")                         
ups.update_all(verification_status: 3)

e depois

rake uploads:fix_missing_s3 

Essa tarefa rake imprimiu mensagens sobre o download de imagens, mas um dia depois, quando as postagens foram reprocessadas, essas imagens aparecem como ![zawfI7C|346x500](upload://9L0PqY4QpqLOfexXHMMbv00EgaB.jpeg) em raw, mas linkam para: https://test.literatecomputing.com/images/transparent.png

2 curtidas

Talvez um script ad hoc onde você:

  1. Liste os arquivos
  2. wget esta lista
  3. aws s3 sync eles para o seu bucket
  4. remap oldbucket newbucket
4 curtidas

Bem, que chato. Eu temia que essa pudesse ser a resposta.

E acho que é assim que o @RGJ também faz. :crying_cat_face:

1 curtida

Mas não consigo listar arquivos porque eles estão no seu bucket e tenho certeza de que preciso de credenciais para uma lista.

rake uploads:fix_missing_s3 parece ter puxado (a maioria?) das coisas para o sistema de arquivos local (os uploads ainda não estão no s3 para este site)

Então eu fiz isso para consertar os uploads:

def fix_bad_uploads(bad_uploads)
  fixed = 0
  retrieved = 0
  missing = 0
  bad_bucket="//discourse-cloud-file-uploads.s3.dualstack.us-west-2.amazonaws.com/business6/uploads/forumosa"
  bad_uploads.each do |upload|
    url = URI.parse("https:"+upload.url)
    upload.url=upload.url.gsub(bad_bucket,"/uploads/default")
    if File.exists?("/shared/#{upload.url}")
      fixed += 1
      print "1"
      upload.save
    # posts = Post.where("raw like '%#{upload.short_url}%'")
    # posts.each do |post|
    #   post.rebake!
    #   print "."
    # end
    else
      begin
        # retrieve missing
        filename = "/shared#{upload.url}"
        dirname = File.dirname(filename)
        unless File.directory?(dirname)
          FileUtils.mkdir_p(dirname)
        end
        file = File.new(filename, "w")
        Net::HTTP.start(url.host) do |http|
          resp = http.get(url.path)
          open(file, "wb") do |file|
            file.write(resp.body)
          end
        end
        file.close
        print "+"
        upload.save if File.exists?(filename)
      rescue => e
        puts "bad: #{e}"
        missing += 0
        sleep 1
        print "0"
      end
    end
  end
end

Isso consertou a maioria deles. Mas parece haver algumas postagens que têm uma entrada uploads:// para a qual não há um Upload no banco de dados. Rebaking essas acaba com um transparent.png.

Então eu tentei algo como isto:

def get_missing_short_url(short_url)
  prefix = "https://discourse-cloud-file-uploads.s3.dualstack.us-west-2.amazonaws.com/business6/uploads/forumosa/original/3X"
  remove_url = "https://discourse-cloud-file-uploads.s3.dualstack.us-west-2.amazonaws.com/business6/uploads/forumosa/"
  sha1= Upload.sha1_from_short_url(short_url)
  extension = short_url.split(".").last
  upload = Upload.find_by(sha1: sha1)
  if !upload
    # try to find it in s3
    one = sha1[0]
    two=sha1[1]
    url_link = "#{prefix}/#{one}/#{two}/#{sha1}.#{extension}"
    puts "URL: #{url_link}"
    sleep 1
    url = URI.parse(url_link)
    full_filename = url_link.gsub(remove_url,"/shared/uploads/default/")
    filename = "/tmp/#{File.basename(url_link.gsub(remove_url,"/shared/uploads/default/"))}"
    dirname = File.dirname(filename)
    unless File.directory?(dirname)
      FileUtils.mkdir_p(dirname)
    end
    File.open(filename, "w") do |file|
      Net::HTTP.start(url.host) do |http|
        resp = http.get(url.path)
        open(file, "wb") do |file|
          file.write(resp.body)
        end
      end
    end
      # make upload for file
    File.open(filename, "r") do |file|
      upload = UploadCreator.new(
        file,
        File.basename(file),
      ).create_for(Discourse.system_user.id)
    end
    if upload.persisted?
      puts "We did it! #{upload.id}"
    else
      puts "darn. #{upload.errors.full_messages}"
      sleep 5
    end
    File.open(filename, "w") do |file|
      Net::HTTP.start(url.host) do |http|
        resp = http.get(url.path)
        open(file, "wb") do |file|
          file.write(resp.body)
        end
      end
    end
    end
  upload
end

Isso funciona na maioria das vezes, mas em meus testes, às vezes falho em inferir o URL S3 correto do sha que infiro do URL curto. Não tenho certeza de como consertar isso.

Além disso, um deles acabou de alguma forma com um sha que era diferente do que estava no nome do arquivo do caminho S3.

Meu pensamento atual agora é começar passando por todos os cooked e obtendo todos os URLs https://discourse-cloud-file-uploads e, em seguida, atualizando os registros Upload que se referem a eles e criando os que estão faltando.

Estou perdendo algo óbvio?

A tabela de uploads não é uma lista de arquivos?

Foi o que pensei! Mas existem alguns uploads:// em raw que não têm entradas na tabela de uploads (pelo menos quando procuro pelo sha fornecido por Upload.sha1_from_short_url(short_url)).

A maioria, mas não todos, eu consegui inferir o URL do bucket a partir do sha (não entendo bem 1X, 2X, 3X, mas parece que todos estão em 3x).

Portanto, não, não é o caso de a tabela de uploads ser uma lista completa dos arquivos em questão.