Răsfoiți Sursa

Merge pull request #3666 from steffann/1814-Ability_to_use_object_store_for_images

Add support for S3 storage for media
Jeremy Stretch 6 ani în urmă
părinte
comite
9a8c8012be

+ 11 - 2
netbox/extras/models.py

@@ -611,11 +611,20 @@ class ImageAttachment(models.Model):
     @property
     def size(self):
         """
-        Wrapper around `image.size` to suppress an OSError in case the file is inaccessible.
+        Wrapper around `image.size` to suppress an OSError in case the file is inaccessible. Also opportunistically
+        catch other exceptions that we know other storage back-ends to throw.
         """
+        expected_exceptions = [OSError]
+
+        try:
+            from botocore.exceptions import ClientError
+            expected_exceptions.append(ClientError)
+        except ImportError:
+            pass
+
         try:
             return self.image.size
-        except OSError:
+        except tuple(expected_exceptions):
             return None
 
 

+ 10 - 0
netbox/netbox/configuration.example.py

@@ -141,6 +141,16 @@ MAX_PAGE_SIZE = 1000
 # the default value of this setting is derived from the installed location.
 # MEDIA_ROOT = '/opt/netbox/netbox/media'
 
+# By default uploaded media is stored on the local filesystem. Using Django-storages is also supported. Provide the
+# class path of the storage driver in STORAGE_BACKEND and any configuration options in STORAGE_CONFIG. For example:
+# STORAGE_BACKEND = 'storages.backends.s3boto3.S3Boto3Storage'
+# STORAGE_CONFIG = {
+#     'AWS_ACCESS_KEY_ID': 'Key ID',
+#     'AWS_SECRET_ACCESS_KEY': 'Secret',
+#     'AWS_STORAGE_BUCKET_NAME': 'netbox',
+#     'AWS_S3_REGION_NAME': 'eu-west-1',
+# }
+
 # Expose Prometheus monitoring metrics at the HTTP endpoint '/metrics'
 METRICS_ENABLED = False
 

+ 19 - 0
netbox/netbox/settings.py

@@ -83,6 +83,8 @@ LOGIN_TIMEOUT = getattr(configuration, 'LOGIN_TIMEOUT', None)
 MAINTENANCE_MODE = getattr(configuration, 'MAINTENANCE_MODE', False)
 MAX_PAGE_SIZE = getattr(configuration, 'MAX_PAGE_SIZE', 1000)
 MEDIA_ROOT = getattr(configuration, 'MEDIA_ROOT', os.path.join(BASE_DIR, 'media')).rstrip('/')
+STORAGE_BACKEND = getattr(configuration, 'STORAGE_BACKEND', None)
+STORAGE_CONFIG = getattr(configuration, 'STORAGE_CONFIG', {})
 METRICS_ENABLED = getattr(configuration, 'METRICS_ENABLED', False)
 NAPALM_ARGS = getattr(configuration, 'NAPALM_ARGS', {})
 NAPALM_PASSWORD = getattr(configuration, 'NAPALM_PASSWORD', '')
@@ -118,6 +120,23 @@ DATABASES = {
     'default': DATABASE,
 }
 
+#
+# Media storage
+#
+
+if STORAGE_BACKEND is not None:
+    DEFAULT_FILE_STORAGE = STORAGE_BACKEND
+
+    if STORAGE_BACKEND.startswith('storages.'):
+        # Monkey-patch Django-storages to also fetch settings from STORAGE_CONFIG
+        import storages.utils
+
+        def _setting(name, default=None):
+            if name in STORAGE_CONFIG:
+                return STORAGE_CONFIG[name]
+            return globals().get(name, default)
+
+        storages.utils.setting = _setting
 
 #
 # Redis