如何从我不拥有的存储桶中提取图像

我有一个网站,上面有很多图片存储在 CDCK 存储桶中。我还有一点时间将它们从该存储桶中取出并移动到本地服务器(然后再移动到另一个存储桶)。

uploads:analyze_missing_s3uploads:fix_missing_s3 rake 任务找不到任何问题,尽管大约有 25,000 张图片存储在远程存储桶中。

功能建议: 似乎 EnsureS3UploadsExistence 应该将上传标记为 invalid_etag,以表示那些不在正确存储桶中的上传(也就是说,没有该存储桶的权限?),但它并没有这样做。我认为,这个任务或其他任务能够注意到上传是否在当前站点没有控制权的存储桶中,或者可能只是站点不期望的存储桶,这才是有意义的。

我不太清楚 verification_status 是什么,因为它似乎并没有验证它是否是好的。

我尝试过的方法

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

然后

 rake uploads:fix_missing_s3 

那个 rake 任务打印了关于下载图片的提示信息,但一天后当帖子被重新烘焙时,这些图片在 raw 中看起来像 ![zawfI7C|346x500](upload://9L0PqY4QpqLOfexXHMMbv00EgaB.jpeg),但链接指向:https://test.literatecomputing.com/images/transparent.png

2 个赞

也许可以写一个临时脚本,其中:

  1. 列出文件
  2. wget 此列表
  3. aws s3 sync 将它们同步到您的存储桶
  4. remap oldbucket newbucket
4 个赞

哎呀,真糟糕。我早就料到会是这个答案。

我想 @RGJ 也是这么做的。 :crying_cat_face:

1 个赞

但我无法列出文件,因为它们在您的存储桶中,而且我确信我需要凭据才能列出。

rake uploads:fix_missing_s3 似乎已将(大部分?)文件提取到本地文件系统(上传文件尚未在 S3 上)。

所以我这样修复了上传文件:

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

这修复了大部分问题。但似乎有些帖子有一个 uploads:// 条目,但数据库中没有对应的 Upload。重新烘焙它们最终会得到一个 transparent.png

然后我尝试了类似这样的方法:

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

这大部分有效,但在我的测试中,有时我无法从我从短 URL 推断出的 sha 中正确推断出 S3 URL。我不确定如何解决这个问题。

另外,其中一个不知何故 ended up with a sha that was different from the one in the filename of the s3 path。

我现在想到的方法是,首先遍历所有 cooked 并获取所有 https://discourse-cloud-file-uploads URL,然后更新指向它们的 Upload 记录并创建缺失的记录。

我是否遗漏了什么明显的问题?

上传表不就是文件列表吗?

我一开始也这么想!但有些 uploads:// 存在于 raw 中,在上传表中却找不到对应的条目(至少当我搜索 Upload.sha1_from_short_url(short_url) 提供的 sha 时是这样)。

我大部分(但不是全部)都能从 sha 推断出存储桶 URL(我不太理解 1X2X3X,但它们似乎都与 3x 相关)。

所以,上传表并不是问题文件的完整列表。