From 26bf1e516e39fc99add4bcf97e7d6c2aebdbb7d0 Mon Sep 17 00:00:00 2001 From: "James E. Blair" Date: Wed, 21 Sep 2022 07:12:31 -0700 Subject: [PATCH] Fix CORS and endpoint in AWS log upload The AWS log upload module does not behave like the rest of the modules: it does not set CORS headers, which means that logs will not be usable in the Zuul web UI without additional manual configuration. The other uploaders all set CORS settings automatically. Correct this in the same way that we do for other clouds. Additionally, if an S3 bucket is created outside of us-east-1, then objects in it must be addressed using the bucket name as hostname, rather than the bare host s3.amazonaws.com. Update the returned URL to use the bucket hostname. This works as well for buckets in us-east-1. Also, fix the command line test invocation. Change-Id: Id92f3cf506b442d0ee5932c6e9d931df19c2cc71 --- .../library/zuul_s3_upload.py | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/roles/upload-logs-base/library/zuul_s3_upload.py b/roles/upload-logs-base/library/zuul_s3_upload.py index 1d0ffd8ff..7e5240de7 100755 --- a/roles/upload-logs-base/library/zuul_s3_upload.py +++ b/roles/upload-logs-base/library/zuul_s3_upload.py @@ -73,11 +73,13 @@ class Uploader(): if endpoint: self.endpoint = endpoint + self.url = os.path.join(endpoint, + bucket, self.prefix) else: self.endpoint = 'https://s3.amazonaws.com/' - - self.url = os.path.join(self.endpoint, - bucket, self.prefix) + return_endpoint = 'https://' + bucket + '.s3.amazonaws.com/' + self.url = os.path.join(return_endpoint, + self.prefix) self.s3 = boto3.resource('s3', endpoint_url=self.endpoint, @@ -85,6 +87,36 @@ class Uploader(): aws_secret_access_key=aws_secret_key) self.bucket = self.s3.Bucket(bucket) + cors = { + 'CORSRules': [{ + 'AllowedMethods': ['GET', 'HEAD'], + 'AllowedOrigins': ['*'], + }] + } + client = boto3.client('s3', + endpoint_url=self.endpoint, + aws_access_key_id=aws_access_key, + aws_secret_access_key=aws_secret_key) + try: + current_cors = None + try: + current_cors = client.get_bucket_cors(Bucket=bucket) + except Exception as e: + # If the error is that we don't have any CORES rules, + # that's okay. + if 'NoSuchCORSConfiguration' not in str(e): + raise + if current_cors: + if current_cors['CORSRules'] != cors['CORSRules']: + current_cors = None + if not current_cors: + client.put_bucket_cors(Bucket=bucket, + CORSConfiguration=cors) + except Exception as e: + # MinIO (which we use in testing) doesn't implement this method + if 'MalformedXML' not in str(e): + raise + def upload(self, file_list): """Spin up thread pool to upload to storage""" @@ -296,7 +328,7 @@ def cli_main(): logging.basicConfig(level=logging.DEBUG) logging.captureWarnings(True) - url = run(args.bucket, args.files, + url = run(args.bucket, files=args.files, prefix=args.prefix, public=not args.no_public, endpoint=args.endpoint)