Fix attachments stored in FS instead of object storage

Assume the following situation:

* We have installed addons base, sale and attachment_s3 (hence
base_attachment_object_storage as dependency)
* All attachments are in S3 already
* We run an upgrade of the 'base' addon, 'sale' is upgraded before
attachment_s3 in the order of loading.
* Sale updates the icon of the Sale menu
* As attachment_s3 is not loaded yet, the attachment is created in the
filestore

Now if we don't persist the filestore or use different servers, we'll
lose the images of the menus (or any attachment loaded by the
install/upgrade of an addon).

The implemented solution is to move the attachments from the filestore
to the object storage at the loading of the module. However, this
operation can take time and it shouldn't be run by 2 processes at the
same time, so we want to detect if the module is loaded during a normal odoo
startup or when some addons have been upgraded. There is nothing anymore
at this point which allow us to know that modules just have been
upgraded except... in the caller frame (load_modules). We have to rely
on the inpect module and get the caller frame, which is not recommended,
but seems the only way, besides, it's not called often and if
_register_hook was called from another place, it would have no effect
(unless the other place has a variable 'update_module' too).
This commit is contained in:
Guewen Baconnier
2018-06-13 17:15:45 +02:00
parent f915b8a1be
commit ddb7656abd
+26
View File
@@ -4,6 +4,7 @@
import base64
import inspect
import logging
import os
import xml.dom.minidom
@@ -91,6 +92,31 @@ class IrAttachment(models.Model):
continue
self._data_set('datas', attach.datas, None)
def _register_hook(self, cr):
super(IrAttachment, self)._register_hook(cr)
curframe = inspect.currentframe()
calframe = inspect.getouterframes(curframe, 2)
# the caller of _register_hook is 'load_modules' in
# odoo/modules/loading.py
# We have to go up 2 stacks because of the old api wrapper
load_modules_frame = calframe[2][0]
# 'update_module' is an argument that 'load_modules' receives with a
# True-ish value meaning that an install or upgrade of addon has been
# done during the initialization. We need to move the attachments that
# could have been created or updated in other addons before this addon
# was loaded
update_module = load_modules_frame.f_locals.get('update_module')
# We need to call the migration on the loading of the model because
# when we are upgrading addons, some of them might add attachments.
# To be sure they are migrated to the storage we need to call the
# migration here.
# Typical example is images of ir.ui.menu which are updated in
# ir.attachment at every upgrade of the addons
if update_module:
env = api.Environment(cr, openerp.SUPERUSER_ID, {})
env['ir.attachment']._force_storage_s3()
@api.multi
def _store_in_db_when_s3(self):
""" Return whether an attachment must be stored in db