Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Azure Blob Storage media backend #303

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

terricain
Copy link

Adds a MediaStorage plugin for Azure Blob Storage


_, blob_service_client = self.get_client()

now = datetime.datetime.now(datetime.UTC)
Copy link
Member

Choose a reason for hiding this comment

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

It looks like the tests are failing because of this on older Python versions - we'll have to use datetime.timezone.utc.

Copy link
Author

Choose a reason for hiding this comment

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

Ah yep, makes sense 😄. Should be fixed now

@dantownsend
Copy link
Member

@terricain Thanks for this!

@codecov-commenter
Copy link

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

Attention: Patch coverage is 93.98496% with 8 lines in your changes missing coverage. Please review.

Project coverage is 90.36%. Comparing base (9cc0966) to head (3565b00).
Report is 17 commits behind head on master.

Files with missing lines Patch % Lines
piccolo_api/media/azure.py 93.98% 8 Missing ⚠️

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #303      +/-   ##
==========================================
- Coverage   92.69%   90.36%   -2.33%     
==========================================
  Files          34       43       +9     
  Lines        2053     2596     +543     
==========================================
+ Hits         1903     2346     +443     
- Misses        150      250     +100     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Member

@dantownsend dantownsend left a comment

Choose a reason for hiding this comment

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

Thanks a lot for this - sorry it took me a while to get around to reviewing it.

I think it looks great, just left some minor comments 👍

Comment on lines +164 to +165
sys.exit(
"Specified connection string did not contain AccountKey"
Copy link
Member

Choose a reason for hiding this comment

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

Maybe we just raise a ValueError here


if not self.sign_urls:
return (
f"https://{self.storage_account_name}.blob.core.windows.net/"
Copy link
Member

@dantownsend dantownsend Nov 15, 2024

Choose a reason for hiding this comment

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

Is it worth having blob.core.windows.net as a class variable, so someone can override this somehow if needed? Just in case there are other services which are API compatible with Azure storage.

storage_account_name: str,
container_name: str,
folder_name: t.Optional[str] = None,
connection_kwargs: t.Optional[t.Dict[str, t.Any]] = None,
Copy link
Member

Choose a reason for hiding this comment

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

We don't really use connection_kwargs for much at the moment - it is just being used as a way of passing a connection string.

Should we pass the connection_kwargs to DefaultAzureCredential? I know the user can set most of the options via environment variables, but it might be convenient to pass them in directly.

https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.defaultazurecredential?view=azure-python#constructor

In which case, connection string, could be a separate argument, or:

connection_kwargs: t.Optional[t.Dict[str, t.Any]] | str = None

If it's a string, we treat it as a connection string.

What do you think?

Comment on lines +150 to +157
if "connection_string" in self.connection_kwargs:
self.connection_string = self.connection_kwargs[
"connection_string"
]
elif "AZURE_STORAGE_CONNECTION_STRING" in os.environ:
self.connection_string = os.environ[
"AZURE_STORAGE_CONNECTION_STRING"
]
Copy link
Member

Choose a reason for hiding this comment

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

Not really a big deal, but we can use the walrus operator to simplify this a little bit.

if connection_string := (
    self.connection_kwargs.get("connection_string")
    or os.environ.get("AZURE_STORAGE_CONNECTION_STRING")
):
    self.connection_string = connection_string

Comment on lines +186 to +187
f"https://{self.storage_account_name}.blob.core.windows.net"
)
Copy link
Member

Choose a reason for hiding this comment

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

We reference this URL in quite a few places - what do you think about setting it in the constructor, so we just do self.account_url = f'https://{self.storage_account_name}.blob.core.windows.net' and then reference self.account_url in the rest of the code?

self.container_name
)

return container_client, blob_service_client
Copy link
Member

Choose a reason for hiding this comment

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

I don't know a huge amount about Azure, and the differences between the two clients. We could split this into two separate methods ... one for each client type ... not sure. We can leave it as is for now.

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.

3 participants