Skip to content

Commit

Permalink
(2.6.0b0) Project has been updated for MinIO SDK 7.0.0:
Browse files Browse the repository at this point in the history
  - New management command: is_minio_available
  - New property: MinioBackend.base_url
  - Dropped support for 2.1 and below
  - Minimum versions raised:
    - Django >= 2.2.2
    - minio >= 7.0.0
  • Loading branch information
theriverman committed Dec 12, 2020
1 parent 5ac4819 commit dae1720
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 29 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[![Actions Status](https://github.com/theriverman/django-minio-backend/workflows/build-n-publish/badge.svg)](https://github.com/theriverman/django-minio-backend/actions)
[![Actions Status](https://github.com/theriverman/django-minio-backend/workflows/publish-py-dist-to-pypi/badge.svg)](https://github.com/theriverman/django-minio-backend/actions)
[![PYPI](https://img.shields.io/pypi/v/django-minio-backend.svg)](https://pypi.python.org/pypi/django-minio-backend)

# django-minio-backend
Expand Down
23 changes: 23 additions & 0 deletions django_minio_backend/management/commands/is_minio_available.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from django.core.management.base import BaseCommand, CommandError
from django_minio_backend.models import MinioBackend


class Command(BaseCommand):
help = 'Checks if the configured MinIO service is available.'

def add_arguments(self, parser):
parser.add_argument('--silenced', action='store_true', default=False, help='No console messages')

def handle(self, *args, **options):
m = MinioBackend('') # no configured bucket
silenced = options.get('silenced')
self.stdout.write(f"Checking the availability of MinIO at {m.base_url}\n") if not silenced else None

available = m.is_minio_available()
if not available:
self.stdout.flush()
raise CommandError(f'MinIO is NOT available at {m.base_url}\n'
f'Reason: {available.details}')

self.stdout.write(f'MinIO is available at {m.base_url}', ending='\n') if not silenced else None
self.stdout.flush()
31 changes: 18 additions & 13 deletions django_minio_backend/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@

# noinspection PyPackageRequirements minIO_requirement
import certifi
import minio.definitions
import minio
import minio.datatypes
import minio.error
import minio.helpers
# noinspection PyPackageRequirements minIO_requirement
import urllib3
from django.core.files import File
from django.core.files.storage import Storage
from django.core.files.uploadedfile import InMemoryUploadedFile
from django.utils.deconstruct import deconstructible
from django.utils.timezone import utc
from minio import Minio

from .utils import MinioServerStatus, PrivatePublicMixedError, ConfigurationError, get_setting

Expand Down Expand Up @@ -56,12 +57,14 @@ def __init__(self,

self._REPLACE_EXISTING = kwargs.get('replace_existing', False)

self.__CLIENT: Union[Minio, None] = None
self.__CLIENT: Union[minio.Minio, None] = None
self.__MINIO_ENDPOINT: str = get_setting("MINIO_ENDPOINT")
self.__MINIO_ACCESS_KEY: str = get_setting("MINIO_ACCESS_KEY")
self.__MINIO_SECRET_KEY: str = get_setting("MINIO_SECRET_KEY")
self.__MINIO_USE_HTTPS: bool = get_setting("MINIO_USE_HTTPS")

self.__BASE_URL = ("https://" if self.__MINIO_USE_HTTPS else "http://") + self.__MINIO_ENDPOINT

self.PRIVATE_BUCKETS: List[str] = get_setting("MINIO_PRIVATE_BUCKETS", [])
self.PUBLIC_BUCKETS: List[str] = get_setting("MINIO_PUBLIC_BUCKETS", [])

Expand Down Expand Up @@ -124,12 +127,12 @@ def _open(self, object_name, mode='rb', **kwargs):
resp.release_conn()
return file

def stat(self, name: str) -> Union[minio.definitions.Object, bool]:
def stat(self, name: str) -> Union[minio.datatypes.Object, bool]:
object_name = Path(name).as_posix()
try:
obj = self.client.stat_object(self._BUCKET_NAME, object_name=object_name)
return obj
except (minio.error.NoSuchKey, minio.error.NoSuchBucket):
except (minio.error.S3Error, minio.error.ServerError):
return False
except urllib3.exceptions.MaxRetryError:
return False
Expand All @@ -152,7 +155,7 @@ def exists(self, name: str) -> bool:
return False

def listdir(self, bucket_name: str):
objects = self.client.list_objects_v2(bucket_name=bucket_name, recursive=True)
objects = self.client.list_objects(bucket_name=bucket_name, recursive=True)
return [(obj.object_name, obj) for obj in objects]

def size(self, name: str) -> int:
Expand All @@ -171,8 +174,7 @@ def url(self, name: str):
:return: (str) URL to object
"""
if self.is_bucket_public:
# noinspection PyProtectedMember
return f'{self.client._endpoint_url}/{self._BUCKET_NAME}/{name}'
return f'{self.__BASE_URL}/{self._BUCKET_NAME}/{name}'

try:
return self.client.presigned_get_object(
Expand Down Expand Up @@ -237,12 +239,11 @@ def is_minio_available(self) -> MinioServerStatus:

with urllib3.PoolManager(cert_reqs=ssl.CERT_REQUIRED, ca_certs=certifi.where()) as http:
try:
scheme = "https" if self.__MINIO_USE_HTTPS else "http"
r = http.request('GET', f'{scheme}://{self.__MINIO_ENDPOINT}/minio/index.html')
r = http.request('GET', f'{self.__BASE_URL}/minio/index.html')
return MinioServerStatus(r)
except urllib3.exceptions.MaxRetryError as e:
mss = MinioServerStatus(None)
mss.add_message(f'Could not open connection to {self.__MINIO_ENDPOINT}/minio/index.html\n'
mss.add_message(f'Could not open connection to {self.__BASE_URL}/minio/index.html\n'
f'Reason: {e}')
return mss
except Exception as e:
Expand All @@ -251,12 +252,16 @@ def is_minio_available(self) -> MinioServerStatus:
return mss

@property
def client(self) -> Minio:
def client(self) -> minio.Minio:
if not self.__CLIENT:
self.new_client()
return self.__CLIENT
return self.__CLIENT

@property
def base_url(self) -> str:
return self.__BASE_URL

def new_client(self):
"""
Instantiates a new Minio client and
Expand All @@ -270,7 +275,7 @@ def new_client(self):
'is not configured properly in your settings.py (or equivalent)'
)

mc = Minio(
mc = minio.Minio(
endpoint=self.__MINIO_ENDPOINT,
access_key=self.__MINIO_ACCESS_KEY,
secret_key=self.__MINIO_SECRET_KEY,
Expand Down
16 changes: 7 additions & 9 deletions django_minio_backend/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,20 @@ def __init__(self, request: Union[urllib3.response.HTTPResponse, None]):
self._details: List[str] = []
self.status = None
self.data = None
self.eval()

self.__OK = 'MinIO is available'
self.___NOK = 'MinIO is NOT available'

def eval(self):
if not self._request:
self.add_message('There was no HTTP request provided for MinioServerStatus upon initialisation.')
return False
self.status = self._request.status
self.data = self._request.data.decode() if self._request.data else 'No data available'
if self.status == 403: # Request was a legal, but the server refuses to respond to it -> it's running fine
self._bool = True
else:
self._details.append(self.__OK)
self._details.append('Reason: ' + self.data)
self.status = self._request.status
self.data = self._request.data.decode() if self._request.data else 'No data available'
if self.status == 403: # Request was a legal, but the server refuses to respond to it -> it's running fine
self._bool = True
else:
self._details.append(self.__OK)
self._details.append('Reason: ' + self.data)

def __bool__(self):
return self._bool
Expand Down
6 changes: 3 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Django~=3.1.3
minio~=6.0.0,<7
Django>=2.2.2
minio>=7.0.0
Pillow
setuptools~=50.3.2
setuptools
4 changes: 1 addition & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,11 @@
author_email='[email protected]',
install_requires=[
'Django>=2.2.2',
'minio>=4.0.9,<7'
'minio>=7.0.0'
],
classifiers=[
'Environment :: Web Environment',
'Framework :: Django',
'Framework :: Django :: 2.0',
'Framework :: Django :: 2.1',
'Framework :: Django :: 2.2',
'Framework :: Django :: 3.0',
'Framework :: Django :: 3.1',
Expand Down

0 comments on commit dae1720

Please sign in to comment.