CDCK 버킷에 이미지들이 많이 있는 사이트가 있습니다. 해당 버킷에서 이미지를 가져와 로컬 서버로 이동한 후(그리고 다른 버킷으로 이동) 아직 조금 더 시간이 남아 있습니다.
uploads:analyze_missing_s3와 uploads:fix_missing_s3 레이크 태스크는 약 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
해당 레이크 태스크는 이미지 다운로드에 대한 메시지를 출력했지만, 하루 후 게시물이 다시 베이킹되었을 때 raw에서는 처럼 보이지만, 링크는 https://test.literatecomputing.com/images/transparent.png으로 가리키고 있습니다.
하지만 파일들은 상대방의 버킷에 있고, 목록을 가져오려면 자격 증명(credentials)이 필요할 것이라고 확신하기 때문에 파일 목록을 표시할 수 없습니다.
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
이로 인해 대부분의 문제가 해결되었습니다. 그러나 데이터베이스에 Upload 레코드가 없는 uploads:// 항목이 있는 게시물이 몇 개 있는 것 같습니다. 그런 게시물들을 다시 생성(rebake)하면 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
이것은 대부분 잘 작동했지만, 테스트 중에 short URL에서 추론한 sha로 올바른 S3 URL을 추론하지 못하는 경우가 간혹 있었습니다. 어떻게 수정해야 할지 모르겠습니다.
또한, 그중 하나는 s3 경로 파일명 속의 sha와 다른 sha가 된 것으로 보입니다.
현재 제 생각은 cooked 필드를 모두 순회하여 https://discourse-cloud-file-uploads URL을 모두 가져온 다음, 그것들을 참조하는 Upload 레코드를 업데이트하고 누락된 것을 생성하는 방식으로 시작하는 것입니다.