1
# Software License Agreement (BSD License)
3
# Copyright (c) 2009-2011, Eucalyptus Systems, Inc.
6
# Redistribution and use of this software in source and binary forms, with or
7
# without modification, are permitted provided that the following conditions
10
# Redistributions of source code must retain the above
11
# copyright notice, this list of conditions and the
12
# following disclaimer.
14
# Redistributions in binary form must reproduce the above
15
# copyright notice, this list of conditions and the
16
# following disclaimer in the documentation and/or other
17
# materials provided with the distribution.
19
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
# POSSIBILITY OF SUCH DAMAGE.
31
# Author: Neil Soman neil@eucalyptus.com
32
# Mitch Garnaat mgarnaat@eucalyptus.com
34
import euca2ools.commands.eucacommand
35
from boto.roboto.param import Param
38
from xml.dom import minidom
39
from boto.exception import S3ResponseError, S3CreateError
40
from boto.s3.key import Key
41
from boto.s3.connection import Location
43
class UploadBundle(euca2ools.commands.eucacommand.EucaCommand):
45
Description = 'Upload a previously bundled image to the cloud.'
46
Options = [Param(name='bucket', short_name='b', long_name='bucket',
47
optional=False, ptype='string',
48
doc='Name of the bucket to upload to.'),
49
Param(name='manifest_path',
50
short_name='m', long_name='manifest',
51
optional=False, ptype='file',
52
doc='Path to the manifest file for bundled image.'),
53
Param(name='canned_acl', long_name='acl',
54
optional=True, ptype='string', default='aws-exec-read',
55
doc='Canned access policy'),
56
Param(name='ec2cert_path', long_name='ec2cert',
57
optional=True, ptype='file',
58
doc="Path to the Cloud's X509 public key certificate."),
59
Param(name='bundle_path',
60
short_name='d', long_name='directory',
61
optional=True, ptype='string',
62
doc="""The directory containing the bundled
63
image to upload (defaults to the manifest directory)."""),
64
Param(name='part', long_name='part',
65
optional=True, ptype='integer',
66
doc='Uploads specified part and all subsequent parts.'),
67
Param(name='skip_manifest', long_name='skipmanifest',
68
optional=True, ptype='boolean', default=False,
69
doc='Do not upload the manifest.'),
70
Param(name='location', long_name='location',
71
optional=True, ptype='string', default=Location.DEFAULT,
72
doc="""The location of the destination S3 bucket
73
Valid values: US|EU|us-west-1|ap-southeast-1|ap-northeast-1""")]
75
def ensure_bucket(self, acl, location=Location.DEFAULT):
76
bucket_instance = None
77
s3conn = self.make_connection_cli('s3')
79
print 'Checking bucket:', self.bucket
80
bucket_instance = s3conn.get_bucket(self.bucket)
82
if location != bucket_instance.get_location():
83
msg = 'Supplied location does not match bucket location'
84
self.display_error_and_exit(msg)
85
except S3ResponseError, s3error:
86
s3error_string = '%s' % s3error
87
if s3error_string.find('404') >= 0:
89
print 'Creating bucket:', self.bucket
90
bucket_instance = s3conn.create_bucket(self.bucket,
94
msg = 'Unable to create bucket %s' % self.bucket
95
self.display_error_and_exit(msg)
96
elif s3error_string.find('403') >= 0:
97
msg = 'You do not have permission to access bucket:', self.bucket
98
self.display_error_and_exit(msg)
100
self.display_error_and_exit(s3error_string)
101
return bucket_instance
103
def get_parts(self, manifest_filename):
105
dom = minidom.parse(manifest_filename)
106
manifest_elem = dom.getElementsByTagName('manifest')[0]
107
parts_list = manifest_elem.getElementsByTagName('filename')
108
for part_elem in parts_list:
109
nodes = part_elem.childNodes
111
if node.nodeType == node.TEXT_NODE:
112
parts.append(node.data)
115
def upload_manifest(self, bucket_instance, manifest_filename,
116
canned_acl=None, upload_policy=None,
117
upload_policy_signature=None):
118
print 'Uploading manifest file'
119
k = Key(bucket_instance)
120
k.key = self.get_relative_filename(manifest_filename)
121
manifest_file = open(manifest_filename, 'rb')
124
headers['S3UploadPolicy'] = upload_policy
125
if upload_policy_signature:
126
headers['S3UploadPolicySignature']=upload_policy_signature
129
k.set_contents_from_file(manifest_file, policy=canned_acl,
131
except S3ResponseError, s3error:
132
s3error_string = '%s' % s3error
133
if s3error_string.find('403') >= 0:
134
msg = 'Permission denied while writing:', k.key
137
self.display_error_and_exit(msg)
139
def upload_parts(self, bucket_instance, directory, parts,
140
part_to_start_from, canned_acl=None,
141
upload_policy=None, upload_policy_signature=None):
142
if part_to_start_from:
143
okay_to_upload = False
145
okay_to_upload = True
149
headers['S3UploadPolicy'] = upload_policy
150
if upload_policy_signature:
151
headers['S3UploadPolicySignature']=upload_policy_signature
154
if part == part_to_start_from:
155
okay_to_upload = True
157
print 'Uploading part:', part
158
k = Key(bucket_instance)
160
part_file = open(os.path.join(directory, part), 'rb')
162
k.set_contents_from_file(part_file, policy=canned_acl,
164
except S3ResponseError, s3error:
165
s3error_string = '%s' % s3error
166
if s3error_string.find('403') >= 0:
167
msg = 'Permission denied while writing:', k.key
170
self.display_error_and_exit(msg)
173
bucket_instance = self.ensure_bucket(self.canned_acl, self.location)
174
parts = self.get_parts(self.manifest_path)
175
manifest_directory, manifest_file = os.path.split(self.manifest_path)
176
if not self.bundle_path:
177
self.bundle_path = manifest_directory
178
if not self.skip_manifest and not self.part:
179
self.upload_manifest(bucket_instance, self.manifest_path,
181
self.upload_parts(bucket_instance, self.bundle_path,
182
parts, self.part, self.canned_acl)
183
print 'Uploaded image as %s/%s' % (self.bucket,
184
self.get_relative_filename(self.manifest_path))