`
JavaCrazyer
  • 浏览: 2989871 次
  • 性别: Icon_minigender_1
  • 来自: 河南
社区版块
存档分类

使用BOTO进行S3各种操作

阅读更多

BOTO是一个开源的PYTHON发布包,是AWS(AMAZON WEBSERVICE)的PYTHON封装。

近期,我们公司用到国内某知名公司的S3云存储服务,需要调用该公司提供的S3 PYTHON SDK。鉴于该公司没有PYTHON版本的SDK,所以我决定利用开源的BOTO的S3模块稍加改进。在经过easy_install boto之后便开始了BOTO的封装

以下是我最开始封装的代码模型


1)获取S3连接:


 

from boto.s3.connection import S3Connection
conn = S3Connection(S3_ACCESSED_ID, S3_SECRECT_ACCESS_KEY,host=S3_HOST)

 


参数说明:

   S3_HOST是提供开放式云存储服务的公司提供的云主机域名

   S3_ACCESSED_ID, S3_SECRECT_ACCESS_KEY是该公司提供给我们公司的唯一访问标识


2)PUT上传文件

 

 def put(bucket_name, s3_path, local_file): 
       b = conn.get_bucket(bucket_name)
       k = Key(b)
       k.key = s3_path
       k.set_contents_from_filename(local_file,policy='public-read')

  参数说明:

         bucket_name是云主机上的云储存分类标识,类型是字符串,可以说是云储存的第一层目录,比如你们公司可以有mp3,mp4,wma等N个一层目录,也就是所谓的bucket,这个可以通过代码创建,也可以登录到云储存网页的控制台进行手动操作

         local_file指的是你要上传的文件,类型是字符串,就是文件绝对路径

         s3_path就是文件上传到s3后要在s3上生成的目录结构,上传时会在指定的bucket下生成该多级目录,当然目录的结尾肯定是文件名


3)get下载文件

 

def get(bucket_name,s3_path,local_file):
    b = conn.get_bucket(bucket_name)
    key = b.lookup(s3_path)
    key.get_contents_to_filename(local_file)

 该方法的参数与put方法中的解释类似


这些代码如果在普通的机器上测试的话,会发现没有任何问题,包括上传下载删除之类的操作都能够成功进行。实际开发过程我发现,将这些代码部署到提供云存储的一套云虚拟机环境中,所有的代码都会执行失败。这个过程中,经历了千辛万苦,我还是没有发现个中原因,主要是在云虚拟机环境中创建conn连接是成功的,就是执行到conn.get_bucket(bucket_name)这一步始终通不过,我考虑到是否在get_bucket加入headers认证什么的,后来研究源码发现没有什么可以加入的,经历了两天的苦苦挣扎(这期间,我考虑过放弃BOTO,而封装使用该公司非常复杂难以理解的REST接口,后来发现,他们的REST接口在本地机器更是一个操作都执行不成功,更别说是虚拟机环境,到了周末陷入了两难的境地,开源的封装了搞不好,他们REST封装了也搞不好。)我还是选择重新研究这个报错的信息

 

Traceback (most recent call last):
  File "s3tester.py", line 35, in <module>
    main()
  File "s3tester.py", line 22, in main
    s3.get_bucket()
  File "/srv/store/20120913111600/common/file/huaweiyun.py", line 77, in get_bucket
    b = conn.get_bucket('vodmedia', validate=True)
  File "/usr/local/lib/python2.6/dist-packages/boto-2.5.2-py2.6.egg/boto/s3/connection.py", line 391, in get_bucket
    bucket.get_all_keys(headers, maxkeys=0)
  File "/usr/local/lib/python2.6/dist-packages/boto-2.5.2-py2.6.egg/boto/s3/bucket.py", line 360, in get_all_keys
    '', headers, **params)
  File "/usr/local/lib/python2.6/dist-packages/boto-2.5.2-py2.6.egg/boto/s3/bucket.py", line 317, in _get_all
    query_args=s)
  File "/usr/local/lib/python2.6/dist-packages/boto-2.5.2-py2.6.egg/boto/s3/connection.py", line 470, in make_request
    override_num_retries=override_num_retries)
  File "/usr/local/lib/python2.6/dist-packages/boto-2.5.2-py2.6.egg/boto/connection.py", line 913, in make_request
    return self._mexe(http_request, sender, override_num_retries)
  File "/usr/local/lib/python2.6/dist-packages/boto-2.5.2-py2.6.egg/boto/connection.py", line 859, in _mexe
    raise e
socket.gaierror: [Errno -2] Name or service not known

 后来,在始终不愿放弃的情况下艰难搜索,终于发现解决方案

 具体是一下两个网上的建议给了我帮助:

http://www.somic.org/2010/11/16/connecting-to-eucalyptus-walrus-s3-with-boto-and-socket-gaierror/

http://www.eucalyptus.com/eucalyptus-cloud/tools/boto


后来遵照他们的说法,我折腾了两天没发现原因的地方,仅仅因为一个小小的配置就成功了。

那就是创建连接是多加入一个参数:calling_format=calling_format

具体代码为:

 

from boto.s3.connection import S3Connection,OrdinaryCallingFormat
calling_format=OrdinaryCallingFormat()
conn = S3Connection(S3_ACCESSED_ID, S3_SECRECT_ACCESS_KEY,host=S3_HOST,calling_format=calling_format)

 将这段代码改进之后,虚拟机上的一套都能够测试通过,包括最需要的上传下载操作,事实证明遇到难题,千万不要放弃,一定要寻找到答案为止。

    这个代码改进的成功也打消了我对该公司云存储虚拟机的误解:之前我的代码在普通机器上执行完全正常的情况下到了他们虚拟上就执行失败,我当时非常怀疑是他们的虚拟机做了什么特殊的配置限定了代码访问云主机,后来跟他们的技术交流他们说没有任何特殊配置,可是我还是心存怀疑。直到今天发现问题所在,看来我是误解他们了!抱歉。


 

1
0
分享到:
评论
2 楼 18215361994 2016-02-20  
请教一个通过String写入文件的问题:
代码 如下:
b = connection.get_bucket("result")
    print b
    k = Key(b)
    k.key = "forbar"
    print k.md5
    print k.etag

    k.set_contents_from_string("update")

出现异常如下,但是值是写入成功的?麻烦问下这个是什么原因造成的?
Traceback (most recent call last):
  File "/home/baiwenhui/PycharmProjects/test/boto_test.py", line 23, in <module>
    k.set_contents_from_string("update")
  File "/usr/local/lib/python2.7/dist-packages/boto/s3/key.py", line 1424, in set_contents_from_string
    encrypt_key=encrypt_key)
  File "/usr/local/lib/python2.7/dist-packages/boto/s3/key.py", line 1291, in set_contents_from_file
    chunked_transfer=chunked_transfer, size=size)
  File "/usr/local/lib/python2.7/dist-packages/boto/s3/key.py", line 748, in send_file
    chunked_transfer=chunked_transfer, size=size)
  File "/usr/local/lib/python2.7/dist-packages/boto/s3/key.py", line 949, in _send_file_internal
    query_args=query_args
  File "/usr/local/lib/python2.7/dist-packages/boto/s3/connection.py", line 664, in make_request
    retry_handler=retry_handler
  File "/usr/local/lib/python2.7/dist-packages/boto/connection.py", line 1068, in make_request
    retry_handler=retry_handler)
  File "/usr/local/lib/python2.7/dist-packages/boto/connection.py", line 939, in _mexe
    request.body, request.headers)
  File "/usr/local/lib/python2.7/dist-packages/boto/s3/key.py", line 880, in sender
    if not self.should_retry(response, chunked_transfer):
  File "/usr/local/lib/python2.7/dist-packages/boto/s3/key.py", line 981, in should_retry
    '%s vs. %s' % (self.etag, self.md5))
boto.exception.S3DataError: BotoClientError: ETag from S3 did not match computed MD5. 3ac340832f29c11538fbe2d6f75e8bcc vs. 3ac340832f29c11538fbe2d6f75e8bcc
1 楼 jiakon 2014-04-16  
您好!
我试了下您的代码,GET的没问题。PUT会出现一个错误提示:
NameError: global name 'Key' is not defined

这个错误您碰到过吗?

相关推荐

Global site tag (gtag.js) - Google Analytics