使用boto和django无法设置S3中的文件权限

5
我已经尝试解决这个问题大约36小时了,所以希望我没有重复提问或者问一些显而易见的问题。我正在构建一个web应用程序,必须操作我在S3中存储的文件,并将新版本的文件以'public-read'的acl权限重新放回S3中。然后另一个页面允许您查看更新的文件。该应用程序存在于亚马逊EC2服务器上,并连接到亚马逊S3存储桶。
我使用django、celery和boto来实现。我设置了一个celery任务,从我的一个视图中获取一些信息,然后进行处理,并将新文件发布到S3上。我能够成功地从S3获取原始文件,进行操作,并将其重新发布到S3上。唯一不起作用的是更改该文件的权限。因此,当您转到查看页面时,除了无法访问该文件以外,其他都正常运行,报403(禁止)错误。
如果我自己进入S3并将该文件的权限更改为每个人都可以读取,那么它就可以工作。在继续之前,我在我的任务中使用的几乎可行的代码是:
name = 'filename.blah'
conn = boto.connect_s3()
b = conn.get_bucket(settings.AWS_STORAGE_BUCKET_NAME)
grab_from_S3(name,b) # grab file from S3
out_name = conv(name)
send_to_S3(out_name,b)

这里的函数包括:

def grab_from_S3(file,bucket):
    k = Key(bucket)
    k.key = file
    k.get_contents_to_filename(file)

def send_to_S3(file,bucket):
    k = Key(bucket)
    k.key = file
    k.set_contents_from_filename(file)
    k.set_acl('public-read')

conv(name)函数只是进行一些转换操作。所以这个代码几乎都能正常工作,除了文件的权限不是'public-read'。我假设所有的AWS凭证和存储桶名称都已正确从环境中导入,因为它能够将文件推送到S3并从S3中拉取文件。

令人困惑的是,当我从EC2服务器上的venv或最初安装在其中的python中打开python环境,并运行上面显示的所有命令时,它确实可以正常工作。我可以轻松更改权限。当任务运行时,在celery日志中不会抛出任何错误,因此我认为任务实际上没有遇到错误。它只是没有按照预期更改。

我尝试过的事情:

  1. 我尝试使用其他版本的权限函数,例如k.set_contents_from_filename(file,policy='public-read')k.make_public()b.set_acl('public-read',out_name),但这些都没有起作用。
  2. 我将存储桶的权限更改为允许每个人更改权限,但仍然不起作用。
  3. 我尝试将存储桶策略更改为以下内容,但没有效果:

    { "Version": "2008-10-17", "Id": "whatever", "Statement": [ { "Sid": "whatever", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": [ "s3:PutObjectAcl", "s3:PutObject"], "Resource": [ "arn:aws:s3:::bucket_name", "arn:aws:s3:::bucket_name/*" ] } ] }

最后,我真的很困惑,因为我似乎可以在同一EC2实例上的python环境中完成所有这些操作,但不能在运行在该实例上的代码中完成。我已经搜索了很长时间,没有找到任何有效的建议。另一个可能有用的信息(但根据问题可能不相关)是,如果我尝试通过执行类似于上面的命令来连接S3,则会返回错误:

"No handler was ready to authenticate. 1 handlers were checked. ['HmacAuthV1Handler'] Check your credentials"

尽管在任务中运行这些命令时它是有效的(我认为它是错误的访问密钥或秘密访问密钥之类的问题,但它与其他所有内容都有效)。我认为我在需要的boto库的python代码中进行了正确的导入。

我最近刚刚设置了这个实例,所以它几乎拥有最新版本的boto、celery、django等。我可能忘记了一些东西。如果您需要更多信息来回答问题,请告诉我。我真的不知道发生了什么。

非常感谢您的帮助。


里面有很多问题,具体来说,在设置密钥的ACL时,请尝试执行以下操作:k.set_contents_from_filename(file, policy='public-read')。这样可以让您在编写文件时设置ACL,而无需进行单独的操作。 - garnaat
嗨Garnaat,谢谢你的建议。在“我尝试过的事情”部分,我提到了我尝试了所有将密钥设置为'public-read'的变体。你建议的那个是我尝试过的。这绝对是一个好建议,但仍然不起作用。真正让我困惑的是,任何一个变体都可以在Python环境中工作,但在tasks.py代码中却无法工作。感谢你的建议! - barragan
1个回答

7
我自己解决了这个问题,大约花了4天时间,答案一直在我的鼻子底下。为了其他可能遇到这个问题的人着想,我会揭示我的愚蠢。
我对celery非常非常陌生。我没有意识到每次更改celery任务时,必须重新启动worker才能看到更改。以前这从未是我的问题,因为我每次开发时都是自己启动worker,但我最近切换到了作为守护进程运行celery。所以这是我做出的第一个更改,其中celery一直在运行。
答案是我只需要重新启动守护进程,这样它就可以看到我的命令。现在一切都正常了。我去尝试在celery文档或入门指南中查找有关记住在更改时执行此操作或代码被导入但没有看到任何明显的内容。我通过其他答案找到了这个答案:

http://docs.celeryproject.org/en/latest/internals/reference/celery.worker.autoreload.html

这对开发很有用。但我没有看到任何明确的提示新人需要重启worker。也许这是显而易见的,我只是太新了。如果有人知道有关此信息的链接,那么将其发布出来会受到欢迎,因为未来可能有人想要阅读它。抱歉浪费大家的时间。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接