mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	Compare commits
	
		
			2 Commits
		
	
	
		
			2.0.5
			...
			s3-compati
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					bfab9cf517 | ||
| 
						 | 
					61913813fd | 
@@ -12,8 +12,8 @@ running quickly. You can later migrate the uploads to S3 by
 | 
			
		||||
[following the instructions here](#migrating-from-local-uploads-to-amazon-s3-backend).
 | 
			
		||||
 | 
			
		||||
We also support an `S3` backend, which uses the Python `boto` library
 | 
			
		||||
to upload files to Amazon S3 (and, with some work, it should be
 | 
			
		||||
possible to use any other storage provider compatible with `boto`).
 | 
			
		||||
to upload files to Amazon S3 (or an S3-compatible block storage
 | 
			
		||||
provider supported by the `boto` library).
 | 
			
		||||
 | 
			
		||||
## S3 backend configuration
 | 
			
		||||
 | 
			
		||||
@@ -27,24 +27,26 @@ two buckets because the "user avatars" bucket is generally configured
 | 
			
		||||
as world-readable, whereas the "uploaded files" one is not.
 | 
			
		||||
 | 
			
		||||
1. Set `s3_key` and `s3_secret_key` in /etc/zulip/zulip-secrets.conf
 | 
			
		||||
to be the S3 access and secret keys for the IAM account.
 | 
			
		||||
   to be the S3 access and secret keys for the IAM account.
 | 
			
		||||
 | 
			
		||||
1. Set the `S3_AUTH_UPLOADS_BUCKET` and `S3_AVATAR_BUCKET` settings in
 | 
			
		||||
`/etc/zulip/settings.py` to be the names of the S3 buckets you
 | 
			
		||||
created (e.g. `exampleinc-zulip-uploads`).
 | 
			
		||||
   `/etc/zulip/settings.py` to be the names of the S3 buckets you
 | 
			
		||||
   created (e.g. `exampleinc-zulip-uploads`).
 | 
			
		||||
 | 
			
		||||
1. Comment out the `LOCAL_UPLOADS_DIR` setting in
 | 
			
		||||
`/etc/zulip/settings.py` (add a `#` at the start of the line).
 | 
			
		||||
   `/etc/zulip/settings.py` (add a `#` at the start of the line).
 | 
			
		||||
 | 
			
		||||
1. In some AWS regions, you need to explicitly
 | 
			
		||||
    [configure boto](http://boto.cloudhackers.com/en/latest/boto_config_tut.html)
 | 
			
		||||
    to use AWS's SIGv4 signature format (because AWS has stopped
 | 
			
		||||
    supporting the older v3 format in those regions).  You can do this
 | 
			
		||||
1. If you are using a non-AWS block storage provider, or certain AWS
 | 
			
		||||
   regions, you may need to explicitly
 | 
			
		||||
   [configure boto](http://boto.cloudhackers.com/en/latest/boto_config_tut.html).
 | 
			
		||||
   For AWS, you may need to use AWS's SIGv4 signature format (because AWS has stopped
 | 
			
		||||
    supporting the older v3 format in those regions); for other
 | 
			
		||||
   providers, you may just need to set the hostname.  You can do this
 | 
			
		||||
    by adding an `/etc/zulip/boto.cfg` containing the following:
 | 
			
		||||
    ```
 | 
			
		||||
    [s3]
 | 
			
		||||
    use-sigv4 = True
 | 
			
		||||
    # Edit to provide your S3 bucket's AWS region here.
 | 
			
		||||
    # Edit to provide your bucket's AWS region or hostname here.
 | 
			
		||||
    host = s3.eu-central-1.amazonaws.com
 | 
			
		||||
    ```
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -322,9 +322,11 @@ def get_realm_for_filename(path: str) -> Optional[int]:
 | 
			
		||||
    return get_user_profile_by_id(key.metadata["user_profile_id"]).realm_id
 | 
			
		||||
 | 
			
		||||
class S3UploadBackend(ZulipUploadBackend):
 | 
			
		||||
    def __init__(self) -> None:
 | 
			
		||||
        self.connection = S3Connection(settings.S3_KEY, settings.S3_SECRET_KEY)
 | 
			
		||||
 | 
			
		||||
    def delete_file_from_s3(self, path_id: str, bucket_name: str) -> bool:
 | 
			
		||||
        conn = S3Connection(settings.S3_KEY, settings.S3_SECRET_KEY)
 | 
			
		||||
        bucket = get_bucket(conn, bucket_name)
 | 
			
		||||
        bucket = get_bucket(self.connection, bucket_name)
 | 
			
		||||
 | 
			
		||||
        # check if file exists
 | 
			
		||||
        key = bucket.get_key(path_id)
 | 
			
		||||
@@ -415,9 +417,7 @@ class S3UploadBackend(ZulipUploadBackend):
 | 
			
		||||
        self.delete_file_from_s3(path_id, bucket_name)
 | 
			
		||||
 | 
			
		||||
    def get_avatar_key(self, file_name: str) -> Key:
 | 
			
		||||
        conn = S3Connection(settings.S3_KEY, settings.S3_SECRET_KEY)
 | 
			
		||||
        bucket_name = settings.S3_AVATAR_BUCKET
 | 
			
		||||
        bucket = get_bucket(conn, bucket_name)
 | 
			
		||||
        bucket = get_bucket(self.connection, settings.S3_AVATAR_BUCKET)
 | 
			
		||||
 | 
			
		||||
        key = bucket.get_key(file_name)
 | 
			
		||||
        return key
 | 
			
		||||
@@ -436,7 +436,8 @@ class S3UploadBackend(ZulipUploadBackend):
 | 
			
		||||
        bucket = settings.S3_AVATAR_BUCKET
 | 
			
		||||
        medium_suffix = "-medium.png" if medium else ""
 | 
			
		||||
        # ?x=x allows templates to append additional parameters with &s
 | 
			
		||||
        return "https://%s.s3.amazonaws.com/%s%s?x=x" % (bucket, hash_key, medium_suffix)
 | 
			
		||||
        return "https://%s.%s/%s%s?x=x" % (bucket, self.connection.DefaultHost,
 | 
			
		||||
                                           hash_key, medium_suffix)
 | 
			
		||||
 | 
			
		||||
    def upload_realm_icon_image(self, icon_file: File, user_profile: UserProfile) -> None:
 | 
			
		||||
        content_type = guess_type(icon_file.name)[0]
 | 
			
		||||
@@ -466,7 +467,8 @@ class S3UploadBackend(ZulipUploadBackend):
 | 
			
		||||
    def get_realm_icon_url(self, realm_id: int, version: int) -> str:
 | 
			
		||||
        bucket = settings.S3_AVATAR_BUCKET
 | 
			
		||||
        # ?x=x allows templates to append additional parameters with &s
 | 
			
		||||
        return "https://%s.s3.amazonaws.com/%s/realm/icon.png?version=%s" % (bucket, realm_id, version)
 | 
			
		||||
        return "https://%s.%s/%s/realm/icon.png?version=%s" % (
 | 
			
		||||
            bucket, self.connection.DefaultHost, realm_id, version)
 | 
			
		||||
 | 
			
		||||
    def upload_realm_logo_image(self, logo_file: File, user_profile: UserProfile,
 | 
			
		||||
                                night: bool) -> None:
 | 
			
		||||
@@ -505,15 +507,15 @@ class S3UploadBackend(ZulipUploadBackend):
 | 
			
		||||
            file_name = 'logo.png'
 | 
			
		||||
        else:
 | 
			
		||||
            file_name = 'night_logo.png'
 | 
			
		||||
        return "https://%s.s3.amazonaws.com/%s/realm/%s?version=%s" % (bucket, realm_id, file_name, version)
 | 
			
		||||
        return "https://%s.%s/%s/realm/%s?version=%s" % (
 | 
			
		||||
            bucket, self.connection.DefaultHost, realm_id, file_name, version)
 | 
			
		||||
 | 
			
		||||
    def ensure_medium_avatar_image(self, user_profile: UserProfile) -> None:
 | 
			
		||||
        file_path = user_avatar_path(user_profile)
 | 
			
		||||
        s3_file_name = file_path
 | 
			
		||||
 | 
			
		||||
        bucket_name = settings.S3_AVATAR_BUCKET
 | 
			
		||||
        conn = S3Connection(settings.S3_KEY, settings.S3_SECRET_KEY)
 | 
			
		||||
        bucket = get_bucket(conn, bucket_name)
 | 
			
		||||
        bucket = get_bucket(self.connection, bucket_name)
 | 
			
		||||
        key = bucket.get_key(file_path + ".original")
 | 
			
		||||
        image_data = key.get_contents_as_string()
 | 
			
		||||
 | 
			
		||||
@@ -533,8 +535,7 @@ class S3UploadBackend(ZulipUploadBackend):
 | 
			
		||||
        s3_file_name = file_path
 | 
			
		||||
 | 
			
		||||
        bucket_name = settings.S3_AVATAR_BUCKET
 | 
			
		||||
        conn = S3Connection(settings.S3_KEY, settings.S3_SECRET_KEY)
 | 
			
		||||
        bucket = get_bucket(conn, bucket_name)
 | 
			
		||||
        bucket = get_bucket(self.connection, bucket_name)
 | 
			
		||||
        key = bucket.get_key(file_path + ".original")
 | 
			
		||||
        image_data = key.get_contents_as_string()
 | 
			
		||||
 | 
			
		||||
@@ -577,7 +578,7 @@ class S3UploadBackend(ZulipUploadBackend):
 | 
			
		||||
        bucket = settings.S3_AVATAR_BUCKET
 | 
			
		||||
        emoji_path = RealmEmoji.PATH_ID_TEMPLATE.format(realm_id=realm_id,
 | 
			
		||||
                                                        emoji_file_name=emoji_file_name)
 | 
			
		||||
        return "https://%s.s3.amazonaws.com/%s" % (bucket, emoji_path)
 | 
			
		||||
        return "https://%s.%s/%s" % (bucket, self.connection.DefaultHost, emoji_path)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Local
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user