Comment extraire des images d'un bucket qui ne m'appartient pas

J’ai un site avec un tas d’images sur un bucket CDCK. J’ai un peu plus de temps pour les extraire de ce bucket et les déplacer vers le serveur local (puis les déplacer vers un autre bucket).

Les tâches rake uploads:analyze_missing_s3 et uploads:fix_missing_s3 ne trouvent aucun problème, même si environ 25 000 images se trouvent sur un bucket distant.

Suggestion de fonctionnalité : Il semble que EnsureS3UploadsExistence devrait marquer les uploads comme invalid_etag pour les uploads qui ne sont pas sur le bon bucket (c’est-à-dire qu’ils n’ont pas les permissions pour ce bucket ?), mais ce n’est pas le cas. Je pense qu’il serait logique que ce job ou un autre job remarque si des uploads se trouvaient sur un bucket que le site actuel ne contrôle pas, ou peut-être que ce n’est tout simplement pas le bucket attendu pour le site.

Je n’arrive pas bien à comprendre ce qu’est verification_status, car il ne semble pas vérifier que c’est quelque chose de bon.

Ce que j’ai essayé

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

et ensuite

 rake uploads:fix_missing_s3 

Cette tâche rake a affiché des messages concernant le téléchargement d’images, mais un jour plus tard, lorsque les posts ont été rebaked, ces images ressemblent à ![zawfI7C|346x500](upload://9L0PqY4QpqLOfexXHMMbv00EgaB.jpeg) dans raw, mais pointent vers : https://test.literatecomputing.com/images/transparent.png

2 « J'aime »

Peut-être un script ad hoc où vous :

  1. Listez les fichiers
  2. Téléchargez cette liste avec wget
  3. Synchronisez-les sur votre bucket avec aws s3 sync
  4. Renommez avec remap oldbucket newbucket
4 « J'aime »

Eh bien, zut. Je craignais que ce soit la réponse.

Et je suppose que c’est comme ça que @RGJ fait aussi. :crying_cat_face:

1 « J'aime »

Mais je ne peux pas lister les fichiers car ils sont sur votre bucket et je suis à peu près sûr d’avoir besoin d’identifiants pour une liste.

rake uploads:fix_missing_s3 semble avoir récupéré (la plupart ?) des éléments vers le système de fichiers local (les téléchargements ne sont pas encore sur s3 pour ce site)

J’ai donc fait ceci pour corriger les téléchargements :

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

Cela a corrigé la plupart d’entre eux. Mais il semble y avoir des messages qui ont une entrée uploads:// pour laquelle il n’y a pas d’Upload dans la base de données. Les refaire aboutit à un transparent.png.

J’ai donc essayé quelque chose comme ceci :

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

Cela fonctionne en grande partie, mais dans mes tests, j’échoue parfois à déduire la bonne URL S3 à partir du sha que je déduis de l’URL courte. Je ne suis pas sûr de la façon de corriger cela.

De plus, l’un d’eux a fini par avoir un sha différent de celui du nom de fichier du chemin s3.

Ma pensée actuelle est de commencer par parcourir tous les cooked et de récupérer toutes les URL https://discourse-cloud-file-uploads, puis de mettre à jour les enregistrements Upload qui y font référence et de créer ceux qui manquent.

Est-ce que je rate quelque chose d’évident ?

La table des téléchargements n’est-elle pas une liste de fichiers ?

C’est ce que je pensais ! Mais il y a des uploads:// qui existent dans raw, qui n’ont pas d’entrées dans la table des uploads (du moins quand je recherche le sha tel que fourni par Upload.sha1_from_short_url(short_url)).

La plupart, mais pas toutes, j’ai pu déduire l’URL du bucket à partir du sha (je ne comprends pas tout à fait 1X, 2X, 3X, mais il semble qu’ils soient tous en 3x).

Donc, non, ce n’est pas le cas que la table des uploads soit une liste complète des fichiers en question.