Skip to content

Conversation

@mihow
Copy link
Collaborator

@mihow mihow commented Oct 1, 2025

Summary

Previously we omitted the region parameter for simplicity because the S3 implementations in the university compute clouds do not use regions and the default region worked for existing AWS S3 users. Now we have some users in Europe that need to specify the S3 region in order for the storage backend to sync, to display source images in the UI, and to processes source images.

List of Changes

  • Adds a region field to the S3StorageSource model
  • Passes region field to necessary functions
  • Fixes some existing type annotation errors

Follow-up: add a region field to the storage source form field in the UI & in the API serializer.

How to Test the Changes

  • Add a storage source in the UI that uses AWS S3 or a provider that supports regions
  • Open the Django admin page for that storage source
  • Add the valid region for your AWS S3 bucket (us-east-1, eu-central-1, etc)
  • Ensure that you can view images in the UI (the private signature URLs should work)
  • Ensure that you can sync a deployment
  • Test existing projects that use regionless storage (OpenStack, JASMIN, etc). Ensure images load & stations can be synced.

Screenshots

Before, when adding an S3 bucket in a European region
image
image

After
image
image

Deployment Notes

  • One migration to add the region filed
  • No UI changes at this time

Checklist

  • I have tested these changes appropriately.
  • I have added and/or modified relevant tests.
  • I updated relevant documentation or comments.
  • I have verified that this PR follows the project's coding standards.
  • Any dependent changes have already been merged to main.

Summary by CodeRabbit

  • New Features
    • S3 storage configuration now supports AWS region specification for improved multi-region deployment capabilities
    • Added region-aware bucket creation functionality with automatic configuration and existing bucket handling

✏️ Tip: You can customize this high-level summary in your review settings.

@mihow mihow marked this pull request as ready for review October 1, 2025 12:16
@netlify
Copy link

netlify bot commented Oct 1, 2025

Deploy Preview for antenna-preview canceled.

Name Link
🔨 Latest commit ef37a55
🔍 Latest deploy log https://app.netlify.com/projects/antenna-preview/deploys/6979478f1d075b0008669209

Copilot AI review requested due to automatic review settings October 1, 2025 12:16
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for S3 regions to enable users in different AWS regions (particularly Europe) to properly configure their S3 storage backends. Previously, the region parameter was omitted for simplicity as university clouds didn't require it and the default region worked for existing AWS users.

  • Adds optional region field to the S3StorageSource model and corresponding configuration
  • Updates S3 client initialization to properly handle region configuration
  • Fixes existing type annotation issues in S3 utility functions

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
ami/main/models.py Adds nullable region field to S3StorageSource model and includes it in the config property
ami/main/migrations/0075_s3storagesource_region.py Database migration to add the region field to existing S3 storage sources
ami/utils/s3.py Updates S3 client/session initialization to use region and fixes type annotations
ami/tests/fixtures/storage.py Updates test fixture to include region parameter
config/settings/base.py Adds S3_TEST_REGION environment variable configuration

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@mihow mihow force-pushed the fix/add-s3-region branch from aff251a to 15a4edd Compare December 6, 2025 00:59
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 6, 2025

📝 Walkthrough

Walkthrough

Adds optional AWS region support across S3 storage: new region field on the S3StorageSource model and S3Config dataclass, boto3 session/client/resource updated to use region, a region-aware create_bucket() helper, fixture updates, admin additions, and a migration to persist the field.

Changes

Cohort / File(s) Summary
Model & Migration
ami/main/models.py, ami/main/migrations/0081_s3storagesource_region.py
Added optional region CharField to S3StorageSource; config now passes region into S3Config. Migration 0081 adds the region field (null=True, blank=True, max_length=255).
S3 Utilities
ami/utils/s3.py
Extended S3Config with `region: str
Tests / Fixtures
ami/tests/fixtures/storage.py
Updated test fixture to include region in S3Config instantiation and defaults for S3StorageSource.
Settings
config/settings/base.py
Added module-level S3_TEST_REGION (sourced from MINIO_REGION / default None).
Admin UI
ami/main/admin.py
S3StorageSourceAdmin list_display reformatted and expanded (adds uri, is_private, project, updated_at), added list_filter = ("project", "bucket"), and new uri/is_private helper methods; slight wording tweak in calculate_size_async message.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Admin as Admin UI
participant Model as S3StorageSource
participant Utils as ami.utils.s3
participant AWS as AWS S3 / MinIO
Admin->>Model: create/update S3StorageSource (includes region)
Model->>Utils: S3Config(...) with region
Utils->>Utils: get_session(region_name=config.region)
Utils->>AWS: create bucket / get client with region_name
AWS-->>Utils: bucket created / client returned
Utils-->>Model: return client/resource or creation result

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I hop through regions, small and grand,
I add a field with careful hand,
Buckets know where they belong,
My boto3 tune sings along—
Hooray, S3 sings in every land! 🐇✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.08% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add support for S3 regions' is concise and accurately summarizes the main change—adding region support to S3 storage configuration.
Description check ✅ Passed The PR description covers most required template sections with clear summaries, detailed testing instructions, deployment notes, and a checklist, though it lacks API/UI form field updates mentioned in follow-up.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
ami/tests/fixtures/storage.py (1)

25-39: Consider passing region to S3StorageSource defaults.

The S3_TEST_CONFIG now includes region, but create_storage_source doesn't pass it to the S3StorageSource.objects.get_or_create defaults. This could lead to inconsistency where the test config has a region but the created storage source doesn't.

         defaults=dict(
             bucket=S3_TEST_CONFIG.bucket_name,
             prefix=prefix,
             endpoint_url=S3_TEST_CONFIG.endpoint_url,
             access_key=S3_TEST_CONFIG.access_key_id,
             secret_key=S3_TEST_CONFIG.secret_access_key,
             public_base_url=S3_TEST_CONFIG.public_base_url,
+            region=S3_TEST_CONFIG.region,
         ),
ami/utils/s3.py (1)

131-139: Consider passing region_name and config to the resource for consistency.

Unlike get_s3_client, this function doesn't explicitly pass region_name or the botocore.config.Config with signature version. While the session inherits the region from get_session(), explicitly passing these parameters would ensure consistent behavior and make the code more explicit.

 def get_resource(config: S3Config) -> S3ServiceResource:
     session = get_session(config)
+    boto_config = botocore.config.Config(signature_version="s3v4")
     s3 = session.resource(
         "s3",
         endpoint_url=config.endpoint_url,
-        # api_version="s3v4",
+        region_name=config.region,
+        config=boto_config,
     )
     s3 = typing.cast(S3ServiceResource, s3)
     return s3
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f899482 and 15a4edd.

📒 Files selected for processing (5)
  • ami/main/migrations/0075_s3storagesource_region.py (1 hunks)
  • ami/main/models.py (2 hunks)
  • ami/tests/fixtures/storage.py (1 hunks)
  • ami/utils/s3.py (6 hunks)
  • config/settings/base.py (1 hunks)
🧰 Additional context used
🪛 Ruff (0.14.7)
ami/main/migrations/0075_s3storagesource_region.py

7-9: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)


11-17: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (9)
config/settings/base.py (1)

448-452: LGTM!

The new S3_TEST_REGION setting follows the established pattern for S3 test configuration and appropriately defaults to None for backward compatibility with existing setups that don't require region specification.

ami/main/models.py (1)

1389-1423: LGTM!

The region field is properly added to S3StorageSource and correctly propagated to S3Config in the config property. The nullable design appropriately maintains backward compatibility for existing storage sources and S3-compatible backends that don't require region specification.

ami/main/migrations/0075_s3storagesource_region.py (1)

1-17: LGTM!

Standard Django migration for adding the nullable region field. The static analysis hints about ClassVar annotations are false positives — Django migrations conventionally define dependencies and operations as class attributes without type annotations.

ami/utils/s3.py (6)

13-13: The boto3.session import is used.

Contrary to the previous review comment, this import is used for the return type annotation on line 94: def get_session(config: S3Config) -> boto3.session.Session. The import should be retained.


33-41: LGTM!

The region field is properly added to the S3Config dataclass with an appropriate None default for backward compatibility.


94-100: LGTM!

The session now correctly receives region_name from the config, ensuring region-aware S3 operations.


103-128: LGTM! The client now consistently uses Signature Version 4 and the region parameter.

Minor note: The credentials are passed to both the session (via get_session) and the client. This redundancy is harmless—the client parameters take precedence—but could be simplified in a future refactor.


599-601: LGTM!

Good improvement extracting Body to a separate variable. The StreamingBody is file-like but type checkers don't recognize it, so the type: ignore comment is appropriate.


684-695: LGTM!

The test function is properly updated with the region=None parameter to match the updated S3Config signature.

@netlify
Copy link

netlify bot commented Dec 24, 2025

Deploy Preview for antenna-ssec canceled.

Name Link
🔨 Latest commit ef37a55
🔍 Latest deploy log https://app.netlify.com/projects/antenna-ssec/deploys/6979478f2302a60008261dc3

mihow and others added 8 commits January 14, 2026 23:30
Ensure consistency between S3_TEST_CONFIG and created S3StorageSource
instances by passing the region parameter to the defaults dict. This
prevents potential inconsistencies where the test config has a region
but the created storage source doesn't.

Co-Authored-By: Claude <noreply@anthropic.com>
Update get_resource() to explicitly pass region_name and botocore
Config with signature version 4, matching the pattern used in
get_s3_client(). This ensures consistent S3 behavior across both
client and resource interfaces.

Co-Authored-By: Claude <noreply@anthropic.com>
AWS requires CreateBucketConfiguration with LocationConstraint for
buckets created outside us-east-1. Updated create_bucket() to handle
this properly while maintaining compatibility with Swift/MinIO.

Added docstring noting this function is primarily used for testing,
as production users create their own buckets.

Co-Authored-By: Claude <noreply@anthropic.com>
Add guidance that Swift/MinIO users should leave the region field
blank, while AWS users should specify their region (e.g., 'us-east-1',
'eu-west-1').

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Collaborator Author

@mihow mihow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested on staging with existing storage configurations and with a new project with images in a European S3 region

@mihow mihow merged commit ae7aa96 into main Jan 27, 2026
7 checks passed
@mihow mihow deleted the fix/add-s3-region branch January 27, 2026 23:28
@mihow
Copy link
Collaborator Author

mihow commented Jan 27, 2026

@coderabbitai add a ticket for adding the region field to the Storage Configuration form modal & backend API (serializer) so that users can configure a region from the UI. Preferably the updated form can introduce a collapsible "Advanced" settings area because we have quite a few fields now.

Also! Please update the HTML for the images in the description of this PR - the images should use their natural width rather than stretching them to full width (just don't specify a width).

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 27, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Fetch the current PR description
gh pr view 962 --json body --jq '.body'

Length of output: 98


@mihow I encountered an authentication limitation in the sandbox environment and cannot directly update the PR description or create the issue. However, I can provide you with the content needed for both:

GitHub Issue to Create

Title: Add region field to Storage Configuration UI with advanced settings section

Body:

## Description
Add support for configuring the S3 region field through the Storage Configuration form modal in the UI.

## Requirements
- [ ] Update the Storage Configuration serializer (backend API) to accept and validate the `region` field
- [ ] Add `region` field to the Storage Configuration form modal
- [ ] Introduce a collapsible "Advanced Settings" section in the form to better organize the growing number of fields
- [ ] Move appropriate fields (including the new `region` field) into the Advanced Settings section
- [ ] Ensure the region field includes appropriate help text (e.g., "AWS region for the S3 bucket. Leave blank for Swift/MinIO storage.")
- [ ] Add client-side validation if needed
- [ ] Update any relevant documentation

## Context
The `region` field was added to the `S3StorageSource` model in PR `#962` but is currently only configurable through the Django admin interface or database directly. Users should be able to configure this through the main UI.

## Related
- PR: https://github.com/RolnickLab/antenna/pull/962
- Comment: https://github.com/RolnickLab/antenna/pull/962#discussion_r[comment_id]

## Assignee
`@mihow`

PR Description Image Fix

For the PR description, please remove the width attribute from any <img> tags. Change any instances like:

<img width="100%" src="...">

to:

<img src="...">

This will allow images to display at their natural width instead of stretching to full width.

Would you like me to try creating the issue through a different method, or can you create it manually with the content above?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants