Merge pull request #365 from yankinmax/mig-object_storage_unsafe_mode

Object Storage - inactive mode
This commit is contained in:
Sébastien Alix
2022-05-18 15:57:29 +02:00
committed by GitHub
co-authored by GitHub
5 changed files with 47 additions and 5 deletions
+5
View File
@@ -162,3 +162,8 @@ environment. It will refuse to start if anything is badly configured.
The checks can be bypassed with the environment variable
`ODOO_CLOUD_PLATFORM_UNSAFE` set to `1`.
### Attachment storage disability
To prevent object storage to be accessed while failing for any kind of reason
set this environment variable `DISABLE_ATTACHMENT_STORAGE` set to `1`.
+7 -1
View File
@@ -1,7 +1,7 @@
Base class for attachments on external object store
===================================================
This is a base addon that regroup common code used by addons targeting specific object store
This is a base addon that regroup common code used by addons targeting specific object store
Configuration
-------------
@@ -38,3 +38,9 @@ Default configuration means:
stored in database
* application/javascript are stored in database whatever their size
* text/css are stored in database whatever their size
Disable attachment storage I/O
------------------------------
Define a environment variable `DISABLE_ATTACHMENT_STORAGE` set to `1`
This will prevent any kind of exceptions and read/write on storage attachments.
@@ -5,6 +5,7 @@ import inspect
import logging
import os
import time
from distutils.util import strtobool
import psycopg2
import odoo
@@ -18,6 +19,10 @@ from odoo.tools.safe_eval import const_eval
_logger = logging.getLogger(__name__)
def is_true(strval):
return bool(strtobool(strval or '0'))
def clean_fs(files):
_logger.info('cleaning old files from filestore')
for full_path in files:
@@ -40,6 +45,18 @@ def clean_fs(files):
class IrAttachment(models.Model):
_inherit = 'ir.attachment'
@staticmethod
def is_storage_disabled(storage=None, log=True):
msg = _("Storages are disabled (see environment configuration).")
if storage:
msg = _(
"Storage '%s' is disabled (see environment configuration)."
) % (storage,)
is_disabled = is_true(os.environ.get("DISABLE_ATTACHMENT_STORAGE"))
if is_disabled and log:
_logger.warning(msg)
return is_disabled
def _register_hook(self):
super()._register_hook()
location = self.env.context.get('storage_location') or self._storage()
@@ -151,6 +168,8 @@ class IrAttachment(models.Model):
``_store_in_db_instead_of_object_storage_domain``.
"""
if self.is_storage_disabled():
return True
storage_config = self._get_storage_force_db_config()
for mimetype_key, limit in storage_config.items():
if mimetype.startswith(mimetype_key):
@@ -190,8 +209,9 @@ class IrAttachment(models.Model):
)
def _store_file_write(self, key, bin_data):
storage = self.storage()
raise NotImplementedError(
'No implementation for %s' % (self.storage(),)
'No implementation for %s' % (storage,)
)
def _store_file_delete(self, fname):
@@ -229,6 +249,8 @@ class IrAttachment(models.Model):
@api.model
def _is_file_from_a_store(self, fname):
for store_name in self._get_stores():
if self.is_storage_disabled(store_name):
continue
uri = '{}://'.format(store_name)
if fname.startswith(uri):
return True
@@ -263,6 +285,9 @@ class IrAttachment(models.Model):
self.ensure_one()
_logger.info('inspecting attachment %s (%d)', self.name, self.id)
fname = self.store_fname
storage = fname.partition('://')[0]
if self.is_storage_disabled(storage):
fname = False
if fname:
# migrating from filesystem filestore
# or from the old 'store_fname' without the bucket name
@@ -305,6 +330,8 @@ class IrAttachment(models.Model):
It is not called anywhere, but can be called by RPC or scripts.
"""
storage = self._storage()
if self.is_storage_disabled(storage):
return
if storage not in self._get_stores():
return
@@ -358,6 +385,8 @@ class IrAttachment(models.Model):
def _force_storage_to_object_storage(self, new_cr=False):
_logger.info('migrating files to the object storage')
storage = self.env.context.get('storage_location') or self._storage()
if self.is_storage_disabled(storage):
return
# The weird "res_field = False OR res_field != False" domain
# is required! It's because of an override of _search in ir.attachment
# which adds ('res_field', '=', False) when the domain does not
+1
View File
@@ -35,6 +35,7 @@ class FileURL(fields.Binary):
'filename': '', # Field to use to store the filename on ir.attachment
}
# pylint: disable=method-required-super
def create(self, record_values):
assert self.attachment
if not record_values:
+4 -3
View File
@@ -35,9 +35,10 @@ class OdooJsonFormatter(jsonlogger.JsonFormatter):
if is_true(os.environ.get('ODOO_LOGGING_JSON')):
format = ('%(asctime)s %(pid)s %(levelname)s'
'%(dbname)s %(name)s: %(message)s')
formatter = OdooJsonFormatter(format)
formatted_message = (
'%(asctime)s %(pid)s %(levelname)s %(dbname)s %(name)s: %(message)s'
)
formatter = OdooJsonFormatter(formatted_message)
logging.getLogger().handlers[0].formatter = formatter