11import logging
22import os
3+ import boto3
4+ from botocore .exceptions import ClientError
35import pecan
46from pecan import response
57from pecan .secure import secure
68from pecan import expose , abort , request
79from webob .static import FileIter
8- from chacra .models import Binary
10+ from chacra .models . binaries import Binary , generate_checksum
911from chacra import models , util
1012from chacra .controllers import error
1113from chacra .controllers .util import repository_is_automatic
@@ -26,6 +28,7 @@ def __init__(self, arch):
2628 self .distro_version = request .context ['distro_version' ]
2729 self .ref = request .context ['ref' ]
2830 self .sha1 = request .context ['sha1' ]
31+ self .checksum = None
2932 request .context ['arch' ] = self .arch
3033
3134 @expose (generic = True , template = 'json' )
@@ -89,7 +92,7 @@ def index_post(self):
8992 if request .POST .get ('force' , False ) is False :
9093 error ('/errors/invalid' , 'resource already exists and "force" key was not used' )
9194
92- full_path = self .save_file (file_obj )
95+ full_path , size = self .save_file (file_obj )
9396
9497 if self .binary is None :
9598 path = full_path
@@ -102,14 +105,17 @@ def index_post(self):
102105 self .binary = Binary (
103106 self .binary_name , self .project , arch = arch ,
104107 distro = distro , distro_version = distro_version ,
105- ref = ref , sha1 = sha1 , path = path , size = os .path .getsize (path )
108+ ref = ref , sha1 = sha1 , path = path , size = size ,
109+ checksum = self .checksum
106110 )
107111 else :
108112 self .binary .path = full_path
113+ self .binary .checksum = self .checksum
109114
110115 # check if this binary is interesting for other configured projects,
111116 # and if so, then mark those other repos so that they can be re-built
112117 self .mark_related_repos ()
118+
113119 return dict ()
114120
115121 def mark_related_repos (self ):
@@ -175,8 +181,32 @@ def save_file(self, file_obj):
175181 for chunk in file_iterable :
176182 f .write (chunk )
177183
184+ size = os .path .getsize (destination )
185+ self .checksum = generate_checksum (destination )
186+
187+ if pecan .conf .storage_method == 's3' :
188+ bucket = pecan .conf .bucket
189+ object_destination = os .path .relpath (destination , pecan .conf .binary_root )
190+
191+ s3_client = boto3 .client ('s3' )
192+ try :
193+ with open (destination , 'rb' ) as f :
194+ s3_client .put_object (Body = f ,
195+ Bucket = bucket ,
196+ Key = object_destination ,
197+ ChecksumAlgorithm = 'sha256' ,
198+ ChecksumSHA256 = self .checksum
199+ )
200+ except ClientError as e :
201+ error ('/errors/error/' , 'file object upload to S3 failed with error %s' % e )
202+
203+ # Remove the local file after S3 upload
204+ os .remove (destination )
205+
206+ destination = 's3://' + object_destination [1 :]
207+
178208 # return the full path to the saved object:
179- return destination
209+ return destination , size
180210
181211 @expose ()
182212 def _lookup (self , name , * remainder ):
0 commit comments