feat: remove unmaintened modules (#443)

This commit is contained in:
Vincent Renaville
2023-11-13 11:33:13 +01:00
committed by GitHub
co-authored by GitHub
parent 25c7d71eb4
commit b1434e34d0
33 changed files with 1 additions and 1072 deletions
-58
View File
@@ -1,58 +0,0 @@
Attachments on S3 storage
=========================
This addon allows to store the attachments (documents and assets) on S3 or any
other S3-compatible Object Storage.
Configuration
-------------
Activate S3 storage:
* Create or set the system parameter with the key ``ir_attachment.location``
and the value in the form ``s3``.
Configure accesses with environment variables:
* ``AWS_HOST`` (not required if using AWS services)
* ``AWS_REGION`` (required if using AWS services)
* ``AWS_ACCESS_KEY_ID``
* ``AWS_SECRET_ACCESS_KEY``
* ``AWS_BUCKETNAME`` (optional {db} placeholder)
Read-only mode:
The bucket and the file key are stored in the attachment. So if you change the
``AWS_BUCKETNAME`` or the ``ir_attachment.location``, the existing attachments
will still be read on their former bucket. But as soon as they are written over
or new attachments are created, they will be created on the new bucket or on
the other location (db or filesystem). This is a convenient way to be able to
read the production attachments on a replication (since you have the
credentials) without any risk to alter the production data.
This addon must be added in the server wide addons with (``--load`` option):
``--load=web,attachment_s3``
The System Parameter ``ir_attachment.storage.force.database`` can be customized to
force storage of files in the database. See the documentation of the module
``base_attachment_object_storage``.
Multi-tenancy
-------------
Use the `{db}` placeholder to handle multi-tenancy.
On instances that hold multiple databases, it's preferable to have one bucket per database.
To handle this, you can insert the `{db}` placeholder in your bucket name variable ``AWS_BUCKETNAME``.
It will be replaced by the database name.
This will give you a unique bucketname per database.
Limitations
-----------
* You need to call ``env['ir.attachment'].force_storage()`` after
having changed the ``ir_attachment.location`` configuration in order to
migrate the existing attachments to S3.
-1
View File
@@ -1 +0,0 @@
from . import models
-19
View File
@@ -1,19 +0,0 @@
# Copyright 2016-2021 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
{
"name": "Attachments on S3 storage",
"summary": "Store assets and attachments on a S3 compatible object storage",
"version": "15.0.1.0.0",
"author": "Camptocamp,Odoo Community Association (OCA)",
"license": "AGPL-3",
"category": "Knowledge Management",
"depends": ["base", "base_attachment_object_storage"],
"external_dependencies": {
"python": ["boto3"],
},
"website": "https://github.com/camptocamp/odoo-cloud-platform",
"data": [],
"installable": False,
}
-1
View File
@@ -1 +0,0 @@
from . import ir_attachment
-177
View File
@@ -1,177 +0,0 @@
# Copyright 2016-2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
import io
import logging
import os
from urllib.parse import urlsplit
from odoo import _, api, exceptions, models
from ..s3uri import S3Uri
_logger = logging.getLogger(__name__)
try:
import boto3
from botocore.exceptions import ClientError, EndpointConnectionError
except ImportError:
boto3 = None # noqa
ClientError = None # noqa
EndpointConnectionError = None # noqa
_logger.debug("Cannot 'import boto3'.")
class IrAttachment(models.Model):
_inherit = "ir.attachment"
def _get_stores(self):
return ["s3"] + super()._get_stores()
@api.model
def _get_s3_bucket(self, name=None):
"""Connect to S3 and return the bucket
The following environment variables can be set:
* ``AWS_HOST``
* ``AWS_REGION``
* ``AWS_ACCESS_KEY_ID``
* ``AWS_SECRET_ACCESS_KEY``
* ``AWS_BUCKETNAME``
If a name is provided, we'll read this bucket, otherwise, the bucket
from the environment variable ``AWS_BUCKETNAME`` will be read.
"""
host = os.environ.get("AWS_HOST")
# Ensure host is prefixed with a scheme (use https as default)
if host and not urlsplit(host).scheme:
host = "https://%s" % host
region_name = os.environ.get("AWS_REGION")
access_key = os.environ.get("AWS_ACCESS_KEY_ID")
secret_key = os.environ.get("AWS_SECRET_ACCESS_KEY")
bucket_name = name or os.environ.get("AWS_BUCKETNAME")
# replaces {db} by the database name to handle multi-tenancy
bucket_name = bucket_name.format(db=self.env.cr.dbname)
params = {
"aws_access_key_id": access_key,
"aws_secret_access_key": secret_key,
}
if host:
params["endpoint_url"] = host
if region_name:
params["region_name"] = region_name
if not (access_key and secret_key and bucket_name):
msg = _(
"If you want to read from the %(bucket_name)s S3 bucket, the following "
"environment variables must be set:\n"
"* AWS_ACCESS_KEY_ID\n"
"* AWS_SECRET_ACCESS_KEY\n"
"If you want to write in the %(bucket_name)s S3 bucket, this variable "
"must be set as well:\n"
"* AWS_BUCKETNAME\n"
"Optionally, the S3 host can be changed with:\n"
"* AWS_HOST\n"
).format(bucket_name=bucket_name)
raise exceptions.UserError(msg)
# try:
s3 = boto3.resource("s3", **params)
bucket = s3.Bucket(bucket_name)
exists = True
try:
s3.meta.client.head_bucket(Bucket=bucket_name)
except ClientError as e:
# If a client error is thrown, then check that it was a 404 error.
# If it was a 404 error, then the bucket does not exist.
error_code = e.response["Error"]["Code"]
if error_code == "404":
exists = False
except EndpointConnectionError as error:
# log verbose error from s3, return short message for user
msg = _logger.exception("Error during connection on S3")
raise exceptions.UserError(str(error)) from None
if not exists:
if not region_name:
bucket = s3.create_bucket(Bucket=bucket_name)
else:
bucket = s3.create_bucket(
Bucket=bucket_name,
CreateBucketConfiguration={"LocationConstraint": region_name},
)
return bucket
@api.model
def _store_file_read(self, fname):
if fname.startswith("s3://"):
s3uri = S3Uri(fname)
try:
bucket = self._get_s3_bucket(name=s3uri.bucket())
except exceptions.UserError:
_logger.exception(
"error reading attachment '%s' from object storage", fname
)
return ""
try:
key = s3uri.item()
bucket.meta.client.head_object(Bucket=bucket.name, Key=key)
with io.BytesIO() as res:
bucket.download_fileobj(key, res)
res.seek(0)
read = res.read()
except ClientError:
read = ""
_logger.info("attachment '%s' missing on object storage", fname)
return read
else:
return super()._store_file_read(fname)
@api.model
def _store_file_write(self, key, bin_data):
location = self.env.context.get("storage_location") or self._storage()
if location == "s3":
bucket = self._get_s3_bucket()
obj = bucket.Object(key=key)
with io.BytesIO() as file:
file.write(bin_data)
file.seek(0)
filename = "s3://%s/%s" % (bucket.name, key)
try:
obj.upload_fileobj(file)
except ClientError as error:
# log verbose error from s3, return short message for user
_logger.exception("Error during storage of the file %s" % filename)
raise exceptions.UserError(
_("The file could not be stored: %s") % str(error)
) from None
else:
_super = super()
filename = _super._store_file_write(key, bin_data)
return filename
@api.model
def _store_file_delete(self, fname):
if fname.startswith("s3://"):
s3uri = S3Uri(fname)
bucket_name = s3uri.bucket()
item_name = s3uri.item()
# delete the file only if it is on the current configured bucket
# otherwise, we might delete files used on a different environment
if bucket_name == os.environ.get("AWS_BUCKETNAME"):
bucket = self._get_s3_bucket()
obj = bucket.Object(key=item_name)
try:
bucket.meta.client.head_object(Bucket=bucket.name, Key=item_name)
obj.delete()
_logger.info("file %s deleted on the object storage" % (fname,))
except ClientError:
# log verbose error from s3, return short message for
# user
_logger.exception("Error during deletion of the file %s" % fname)
else:
return super()._store_file_delete(fname)
-21
View File
@@ -1,21 +0,0 @@
# Copyright 2016-2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
import re
class S3Uri(object):
_url_re = re.compile("^s3:///*([^/]*)/?(.*)", re.IGNORECASE | re.UNICODE)
def __init__(self, uri):
match = self._url_re.match(uri)
if not match:
raise ValueError("%s: is not a valid S3 URI" % (uri,))
self._bucket, self._item = match.groups()
def bucket(self):
return self._bucket
def item(self):
return self._item
-60
View File
@@ -1,60 +0,0 @@
Attachments on Swift storage
============================
This addon enable storing attachments (documents and assets) on OpenStack Object Storage (Swift)
Configuration
-------------
Activate Swift storage:
* Create or set the system parameter with the key ``ir_attachment.location`` with the following value ``swift``.
Configure accesses with environment variables:
* ``SWIFT_AUTH_URL`` : URL of the Swift server
* ``SWIFT_TENANT_NAME`` : **!** DEPRECATED **!** Use ``SWIFT_PROJECT_NAME`` instead
* ``SWIFT_PROJECT_NAME``
* ``SWIFT_ACCOUNT``
* ``SWIFT_PASSWORD``
* ``SWIFT_REGION_NAME`` : optional region
* ``SWIFT_WRITE_CONTAINER`` : Name of the container to use in the store (created if not existing)
Read-only mode:
The container name and the key are stored in the attachment. So if you change the
``SWIFT_WRITE_CONTAINER`` or the ``ir_attachment.location``, the existing attachments
will still be read on their former container. But as soon as they are written over
or new attachments are created, they will be created on the new container or on
the other location (db or filesystem). This is a convenient way to be able to
read the production attachments on a replication (since you have the
credentials) without any risk to alter the production data.
This addon must be added in the server wide addons with (``--load`` option):
``--load=web,attachment_swift``
The System Parameter ``ir_attachment.storage.force.database`` can be customized to
force storage of files in the database. See the documentation of the module
``base_attachment_object_storage``.
Python Dependencies
-------------------
This module needs the python-swiftclient and the python-keystoneclient (For auth v3.0) to work.
The python-keystoneclient needs the linux package build-essential and python-dev to install properly.
The python-swiftclient can be used from the command line, useful to test:
.. code-block:: sh
export AUTH_VERSION=3.0
export OS_USERNAME={SWIFT_ACCOUNT}
export OS_PASSWORD={SWIFT_PASSWORD}
export OS_PROJECT_NAME={SWIFT_PROJECT_NAME}
export OS_REGION_NAME={SWIFT_REGION_NAME}
export OS_AUTH_URL=https://auth.cloud.ovh.net/v3
swift stat
More information at
https://docs.openstack.org/python-swiftclient/latest/cli/index.html#swift-usage
-1
View File
@@ -1 +0,0 @@
from . import models
-23
View File
@@ -1,23 +0,0 @@
# Copyright 2017-2021 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
{
"name": "Attachments on Swift storage",
"summary": "Store assets and attachments on a Swift compatible object store",
"version": "15.0.1.0.0",
"author": "Camptocamp,Odoo Community Association (OCA)",
"license": "AGPL-3",
"category": "Knowledge Management",
"depends": ["base_attachment_object_storage"],
"external_dependencies": {
"python": [
"swiftclient",
"keystoneclient",
"keystoneauth1",
],
},
"website": "https://github.com/camptocamp/odoo-cloud-platform",
"data": [],
"installable": False,
}
-1
View File
@@ -1 +0,0 @@
from . import ir_attachment
-176
View File
@@ -1,176 +0,0 @@
# Copyright 2017-2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
import logging
import os
from odoo import _, api, exceptions, models
from ..swift_uri import SwiftUri
_logger = logging.getLogger(__name__)
try:
import keystoneauth1
import keystoneauth1.identity
import keystoneauth1.session
import swiftclient
from swiftclient.exceptions import ClientException
except ImportError:
swiftclient = None
ClientException = None
_logger.debug("Cannot 'import swiftclient'.")
SWIFT_TIMEOUT = 15
class SwiftSessionStore(object):
"""Keep in memory the current Swift Auth session
The auth endpoint has a rate limit on swift, if every operation
on the filestore authenticate, the limit is exhausted and
operations rejected with an HTTP error code 429.
Swift connections can reuse the same session by asking a session
matching their connection parameters with ``get_session``.
The keystoneauth1's session automatically creates a new token
if the previous one is expired.
The best documentation I found about sessions is
https://docs.openstack.org/keystoneauth/latest/using-sessions.html
"""
def __init__(self):
self._sessions = {}
def _get_key(self, auth_url, username, password, project_name):
return (auth_url, username, password, project_name)
def get_session(
self, auth_url=None, username=None, password=None, project_name=None
):
key = self._get_key(auth_url, username, password, project_name)
session = self._sessions.get(key)
if not session:
auth = keystoneauth1.identity.v3.Password(
username=username,
password=password,
project_name=project_name,
auth_url=auth_url,
project_domain_id="default",
user_domain_id="default",
)
session = keystoneauth1.session.Session(
auth=auth,
timeout=SWIFT_TIMEOUT,
)
self._sessions[key] = session
return session
swift_session_store = SwiftSessionStore()
class IrAttachment(models.Model):
_inherit = "ir.attachment"
def _get_stores(self):
return ["swift"] + super()._get_stores()
@api.model
def _get_swift_connection(self):
"""Returns a connection object for the Swift object store"""
host = os.environ.get("SWIFT_AUTH_URL")
account = os.environ.get("SWIFT_ACCOUNT")
password = os.environ.get("SWIFT_PASSWORD")
project_name = os.environ.get("SWIFT_PROJECT_NAME")
if not project_name and os.environ.get("SWIFT_TENANT_NAME"):
project_name = os.environ["SWIFT_TENANT_NAME"]
_logger.warning(
"SWIFT_TENANT_NAME is deprecated and "
"must be replaced by SWIFT_PROJECT_NAME"
)
region = os.environ.get("SWIFT_REGION_NAME")
os_options = {}
if region:
os_options["region_name"] = region
if not (host and account and password and project_name):
raise exceptions.UserError(
_(
"Problem connecting to Swift store, are the env variables "
"(SWIFT_AUTH_URL, SWIFT_ACCOUNT, SWIFT_PASSWORD, "
"SWIFT_TENANT_NAME) properly set?"
)
)
try:
session = swift_session_store.get_session(
username=account,
password=password,
project_name=project_name,
auth_url=host,
)
conn = swiftclient.client.Connection(
session=session,
os_options=os_options,
)
except ClientException:
_logger.exception("Error connecting to Swift object store")
raise exceptions.UserError(_("Error on Swift connection")) from None
return conn
@api.model
def _store_file_read(self, fname):
if fname.startswith("swift://"):
swifturi = SwiftUri(fname)
try:
conn = self._get_swift_connection()
except exceptions.UserError:
_logger.exception(
"error reading attachment '%s' from object storage", fname
)
return ""
try:
resp, read = conn.get_object(swifturi.container(), swifturi.item())
except ClientException:
read = ""
_logger.exception("Error reading object from Swift object store")
return read
else:
return super()._store_file_read(fname)
def _store_file_write(self, key, bin_data):
if self._storage() == "swift":
container = os.environ.get("SWIFT_WRITE_CONTAINER")
conn = self._get_swift_connection()
conn.put_container(container)
filename = "swift://{}/{}".format(container, key)
try:
conn.put_object(container, key, bin_data)
except ClientException:
_logger.exception("Error writing to Swift object store")
raise exceptions.UserError(_("Error writing to Swift")) from None
else:
_super = super()
filename = _super._store_file_write(key, bin_data)
return filename
@api.model
def _store_file_delete(self, fname):
if fname.startswith("swift://"):
swifturi = SwiftUri(fname)
container = swifturi.container()
# delete the file only if it is on the current configured bucket
# otherwise, we might delete files used on a different environment
if container == os.environ.get("SWIFT_WRITE_CONTAINER"):
conn = self._get_swift_connection()
try:
conn.delete_object(container, swifturi.item())
except ClientException:
_logger.exception(_("Error deleting an object on the Swift store"))
# we ignore the error, file will stay on the object
# storage but won't disrupt the process
else:
return super()._file_delete_from_store(fname)
-21
View File
@@ -1,21 +0,0 @@
# Copyright 2017-2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
import re
class SwiftUri(object):
_url_re = re.compile("^swift:///*([^/]*)/?(.*)", re.IGNORECASE | re.UNICODE)
def __init__(self, uri):
match = self._url_re.match(uri)
if not match:
raise ValueError("%s: is not a valid Swift URI" % (uri,))
self._container, self._item = match.groups()
def container(self):
return self._container
def item(self):
return self._item
-1
View File
@@ -1 +0,0 @@
from . import test_mock_swift_api
@@ -1,120 +0,0 @@
# Copyright 2017-2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
import base64
import os
import keystoneauth1
import mock
from mock import patch
from odoo.addons.attachment_swift.models.ir_attachment import SwiftSessionStore
from odoo.addons.attachment_swift.swift_uri import SwiftUri
from odoo.addons.base.tests.test_ir_attachment import TestIrAttachment
class TestAttachmentSwift(TestIrAttachment):
def setup(self):
res = super().setUp()
self.env["ir.config_parameter"].set_param("ir_attachment.location", "swift")
return res
def test_session_store_get_session(self):
auth_url = "auth_url"
username = "username"
password = "password"
project_name = "project_name"
store = SwiftSessionStore()
session = store.get_session(
auth_url=auth_url,
username=username,
password=password,
project_name=project_name,
)
self.assertEqual(session.auth.auth_url, auth_url)
self.assertEqual(
session.auth.get_cache_id_elements().get("password_username"), username
)
self.assertEqual(
session.auth.get_cache_id_elements().get("password_password"), password
)
self.assertEqual(session.auth.project_name, project_name)
# get the same session on a second call
self.assertEqual(
store.get_session(
auth_url=auth_url,
username=username,
password=password,
project_name=project_name,
),
session,
)
@patch("swiftclient.client")
def test_connection(self, mock_swift_client):
"""Test the connection to the store"""
os.environ["SWIFT_AUTH_URL"] = "auth_url"
os.environ["SWIFT_ACCOUNT"] = "account"
os.environ["SWIFT_PASSWORD"] = "password"
os.environ["SWIFT_PROJECT_NAME"] = "project_name"
os.environ["SWIFT_REGION_NAME"] = "NOWHERE"
attachment = self.Attachment
attachment._get_swift_connection()
mock_swift_client.Connection.assert_called_once_with(
session=mock.ANY,
os_options={"region_name": os.environ.get("SWIFT_REGION_NAME")},
)
__, kwargs = mock_swift_client.Connection.call_args
session = kwargs["session"]
self.assertTrue(isinstance(session, keystoneauth1.session.Session))
self.assertEqual(session.auth.auth_url, os.environ["SWIFT_AUTH_URL"])
self.assertEqual(
session.auth.get_cache_id_elements().get("password_username"),
os.environ["SWIFT_ACCOUNT"],
)
self.assertEqual(
session.auth.get_cache_id_elements().get("password_password"),
os.environ["SWIFT_PASSWORD"],
)
self.assertEqual(session.auth.project_name, os.environ["SWIFT_PROJECT_NAME"])
def test_store_file_on_swift(self):
"""
Test writing a file
"""
(self.env["ir.config_parameter"].set_param("ir_attachment.location", "swift"))
os.environ["SWIFT_AUTH_URL"] = "auth_url"
os.environ["SWIFT_ACCOUNT"] = "account"
os.environ["SWIFT_PASSWORD"] = "password"
os.environ["SWIFT_PROJECT_NAME"] = "project_name"
os.environ["SWIFT_WRITE_CONTAINER"] = "my_container"
container = os.environ.get("SWIFT_WRITE_CONTAINER")
attachment = self.Attachment
bin_data = base64.b64decode(self.blob1_b64)
with patch("swiftclient.client.Connection") as MockConnection:
conn = MockConnection.return_value
attachment.create({"name": "a5", "datas": self.blob1_b64})
conn.put_object.assert_called_with(
container, attachment._compute_checksum(bin_data), bin_data
)
def test_delete_file_on_swift(self):
"""
Test deleting a file
"""
(self.env["ir.config_parameter"].set_param("ir_attachment.location", "swift"))
os.environ["SWIFT_AUTH_URL"] = "auth_url"
os.environ["SWIFT_ACCOUNT"] = "account"
os.environ["SWIFT_PASSWORD"] = "password"
os.environ["SWIFT_PROJECT_NAME"] = "project_name"
os.environ["SWIFT_WRITE_CONTAINER"] = "my_container"
attachment = self.Attachment
container = os.environ.get("SWIFT_WRITE_CONTAINER")
with patch("swiftclient.client.Connection") as MockConnection:
conn = MockConnection.return_value
a5 = attachment.create({"name": "a5", "datas": self.blob1_b64})
uri = SwiftUri(a5.store_fname)
a5.unlink()
conn.delete_object.assert_called_with(container, uri.item())
@@ -1,42 +0,0 @@
# Copyright 2017-2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
from swiftclient.exceptions import ClientException
from odoo.addons.base.tests.test_ir_attachment import TestIrAttachment
from ..swift_uri import SwiftUri
class TestAttachmentSwift(TestIrAttachment):
"""
Those tests are made to be run against a real Swift store (local or remote)
"""
def setup(self):
res = super().setUp()
self.env["ir.config_parameter"].set_param("ir_attachment.location", "swift")
return res
def test_connection(self):
"""Test the connection to the Swift object store"""
conn = self.Attachment._get_swift_connection()
self.assertNotEqual(conn, False)
def test_store_file_on_swift(self):
"""Test writing a file and then reading it"""
(self.env["ir.config_parameter"].set_param("ir_attachment.location", "swift"))
a5 = self.Attachment.create({"name": "a5", "datas": self.blob1_b64})
a5bis = self.Attachment.browse(a5.id)[0]
self.assertEqual(a5.datas, a5bis.datas)
def test_delete_file_on_swift(self):
"""Create a file and then test the deletion"""
(self.env["ir.config_parameter"].set_param("ir_attachment.location", "swift"))
a5 = self.Attachment.create({"name": "a5", "datas": self.blob1_b64})
uri = SwiftUri(a5.store_fname)
con = self.Attachment._get_swift_connection()
con.get_object(uri.container(), uri.item())
a5.unlink()
with self.assertRaises(ClientException):
con.get_object(uri.container(), uri.item())
-5
View File
@@ -1,5 +0,0 @@
# Cloud Platform Exoscale
Install addons specific to the Exoscale setup.
* The object storage is S3
-1
View File
@@ -1 +0,0 @@
from . import models
-23
View File
@@ -1,23 +0,0 @@
# Copyright 2017-2021 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
{
"name": "Cloud Platform Exoscale",
"summary": "Addons required for the Camptocamp Cloud Platform on Exoscale",
"version": "15.0.1.0.0",
"author": "Camptocamp,Odoo Community Association (OCA)",
"license": "AGPL-3",
"category": "Extra Tools",
"depends": [
"cloud_platform",
"attachment_s3",
"monitoring_statsd",
],
"excludes": [
"cloud_platform_ovh",
],
"website": "https://github.com/camptocamp/odoo-cloud-platform",
"data": [],
"installable": False,
}
@@ -1 +0,0 @@
from . import cloud_platform
@@ -1,110 +0,0 @@
# Copyright 2016-2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
import os
import re
from odoo import api, models
from odoo.addons.cloud_platform.models.cloud_platform import (
FilestoreKind,
PlatformConfig,
)
S3_STORE_KIND = FilestoreKind("s3", "remote")
class CloudPlatform(models.AbstractModel):
_inherit = "cloud.platform"
@api.model
def _filestore_kinds(self):
kinds = super(CloudPlatform, self)._filestore_kinds()
kinds["s3"] = S3_STORE_KIND
return kinds
@api.model
def _platform_kinds(self):
kinds = super(CloudPlatform, self)._platform_kinds()
kinds.append("exoscale")
return kinds
@api.model
def _config_by_server_env_for_exoscale(self):
fs_kinds = self._filestore_kinds()
configs = {
"prod": PlatformConfig(filestore=fs_kinds["s3"]),
"integration": PlatformConfig(filestore=fs_kinds["s3"]),
"labs": PlatformConfig(filestore=fs_kinds["s3"]),
"test": PlatformConfig(filestore=fs_kinds["db"]),
"dev": PlatformConfig(filestore=fs_kinds["db"]),
}
return configs
@api.model
def _check_filestore(self, environment_name):
params = self.env["ir.config_parameter"].sudo()
use_s3 = params.get_param("ir_attachment.location") == S3_STORE_KIND.name
if environment_name in ("prod", "integration"):
# Labs instances use s3 by default, but we don't want
# to enforce it in case we want to test something with a different
# storage. At your own risks!
assert use_s3, (
"S3 must be used on production and integration instances. "
"It is activated by setting 'ir_attachment.location.' to 's3'."
" The 'install()' function sets this option "
"automatically."
)
if use_s3:
assert os.environ.get("AWS_ACCESS_KEY_ID"), (
"AWS_ACCESS_KEY_ID environment variable is required when "
"ir_attachment.location is 's3'."
)
assert os.environ.get("AWS_SECRET_ACCESS_KEY"), (
"AWS_SECRET_ACCESS_KEY environment variable is required when "
"ir_attachment.location is 's3'."
)
bucket_name = os.environ.get("AWS_BUCKETNAME", "")
if environment_name in ("prod", "integration", "labs"):
assert bucket_name, (
"AWS_BUCKETNAME environment variable is required when "
"ir_attachment.location is 's3'.\n"
"Normally, 's3' is activated on labs, integration "
"and production, but should not be used in dev environment"
" (or using a dedicated dev bucket, never using the "
"integration/prod bucket).\n"
"If you don't actually need a bucket, change the"
" 'ir_attachment.location' parameter."
)
# A bucket name is defined under the following format
# <client>-odoo-<env>
#
# Use AWS_BUCKETNAME_UNSTRUCTURED to by-pass check on bucket name
# structure
if os.environ.get("AWS_BUCKETNAME_UNSTRUCTURED"):
return
prod_bucket = bool(re.match(r"[a-z-0-9]+-odoo-prod", bucket_name))
if environment_name == "prod":
assert prod_bucket, (
"AWS_BUCKETNAME should match '<client>-odoo-prod', "
"we got: '%s'" % (bucket_name,)
)
else:
# if we are using the prod bucket on another instance
# such as an integration, we must be sure to be in read only!
assert not prod_bucket, (
"AWS_BUCKETNAME should not match '<client>-odoo-prod', "
"we got: '%s'" % (bucket_name,)
)
elif environment_name == "test":
# store in DB so we don't have files local to the host
assert params.get_param("ir_attachment.location") == "db", (
"In test instances, files must be stored in the database with "
"'ir_attachment.location' set to 'db'. This is "
"automatically set by the function 'install()'."
)
@api.model
def install(self):
self._install("exoscale")
-5
View File
@@ -1,5 +0,0 @@
# Cloud Platform OVH
Install addons specific to the OVH setup.
* The object storage is Swift
-1
View File
@@ -1 +0,0 @@
from . import models
-23
View File
@@ -1,23 +0,0 @@
# Copyright 2017-2021 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
{
"name": "Cloud Platform OVH",
"summary": "Addons required for the Camptocamp Cloud Platform on OVH",
"version": "15.0.1.0.0",
"author": "Camptocamp,Odoo Community Association (OCA)",
"license": "AGPL-3",
"category": "Extra Tools",
"depends": [
"cloud_platform",
"attachment_swift",
"monitoring_statsd",
],
"excludes": [
"cloud_platform_exoscale",
],
"website": "https://github.com/camptocamp/odoo-cloud-platform",
"data": [],
"installable": False,
}
-1
View File
@@ -1 +0,0 @@
from . import cloud_platform
-113
View File
@@ -1,113 +0,0 @@
# Copyright 2017-2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
import os
import re
from odoo import api, models
from odoo.addons.cloud_platform.models.cloud_platform import (
FilestoreKind,
PlatformConfig,
)
SWIFT_STORE_KIND = FilestoreKind("swift", "remote")
class CloudPlatform(models.AbstractModel):
_inherit = "cloud.platform"
@api.model
def _filestore_kinds(self):
kinds = super(CloudPlatform, self)._filestore_kinds()
kinds["swift"] = SWIFT_STORE_KIND
return kinds
@api.model
def _platform_kinds(self):
kinds = super()._platform_kinds()
kinds.append("ovh")
return kinds
@api.model
def _config_by_server_env_for_ovh(self):
fs_kinds = self._filestore_kinds()
configs = {
"prod": PlatformConfig(filestore=fs_kinds["swift"]),
"integration": PlatformConfig(filestore=fs_kinds["swift"]),
"labs": PlatformConfig(filestore=fs_kinds["swift"]),
"test": PlatformConfig(filestore=fs_kinds["db"]),
"dev": PlatformConfig(filestore=fs_kinds["db"]),
}
return configs
@api.model
def _check_filestore(self, environment_name):
params = self.env["ir.config_parameter"].sudo()
use_swift = params.get_param("ir_attachment.location") == SWIFT_STORE_KIND.name
if environment_name in ("prod", "integration"):
# Labs instances use swift by default, but we don't want
# to enforce it in case we want to test something with a different
# storage. At your own risks!
assert use_swift, (
"Swift must be used on production and integration instances. "
"It is activated, setting 'ir_attachment.location.' to 'swift'"
" The 'install()' function sets this option "
"automatically."
)
if use_swift:
assert os.environ.get("SWIFT_AUTH_URL"), (
"SWIFT_AUTH_URL environment variable is required when "
"ir_attachment.location is 'swift'."
)
assert os.environ.get("SWIFT_ACCOUNT"), (
"SWIFT_ACCOUNT environment variable is required when "
"ir_attachment.location is 'swift'."
)
assert os.environ.get("SWIFT_PASSWORD"), (
"SWIFT_PASSWORD environment variable is required when "
"ir_attachment.location is 'swift'."
)
container_name = os.environ.get("SWIFT_WRITE_CONTAINER", "")
if environment_name in ("prod", "integration", "labs"):
assert container_name, (
"SWIFT_WRITE_CONTAINER environment variable is required when "
"ir_attachment.location is 'swift'.\n"
"Normally, 'swift' is activated on labs, integration "
"and production, but should not be used in dev environment"
" (or using a dedicated dev bucket, never using the "
"integration/prod bucket).\n"
"If you don't actually need a bucket, change the"
" 'ir_attachment.location' parameter."
)
prod_container = bool(re.match(r"[a-z0-9-]+-odoo-prod", container_name))
# A bucket name is defined under the following format
# <client>-odoo-<env>
#
# Use SWIFT_WRITE_CONTAINER_UNSTRUCTURED to by-pass check on bucket name
# structure
if os.environ.get("SWIFT_WRITE_CONTAINER_UNSTRUCTURED"):
return
if environment_name == "prod":
assert prod_container, (
"SWIFT_WRITE_CONTAINER should match '<client>-odoo-prod', "
"we got: '%s'" % (container_name,)
)
else:
# if we are using the prod bucket on another instance
# such as an integration, we must be sure to be in read only!
assert not prod_container, (
"SWIFT_WRITE_CONTAINER should not match "
"'<client>-odoo-prod', we got: '%s'" % (container_name,)
)
elif environment_name == "test":
# store in DB so we don't have files local to the host
assert params.get_param("ir_attachment.location") == "db", (
"In test instances, files must be stored in the database with "
"'ir_attachment.location' set to 'db'. This is "
"automatically set by the function 'install()'."
)
@api.model
def install(self):
self._install("ovh")
-10
View File
@@ -1,10 +0,0 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License
============================
Kwktnkltopdf Asset
============================
Force assets to be saved to be readable by kwkhtmltopdf server, the
first time you print a report it failed to generate
the pdf asset used for pdf
-1
View File
@@ -1 +0,0 @@
from . import models
-17
View File
@@ -1,17 +0,0 @@
# Copyright 2016-2021 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
{
"name": "Kwkhtmltopdf: Asset fix",
"version": "17.0.1.0.0",
"author": "Camptocamp,Odoo Community Association (OCA)",
"license": "AGPL-3",
"category": "category",
"depends": [
"base",
],
"website": "https://github.com/camptocamp/odoo-cloud-platform",
"data": [],
"installable": True,
}
-1
View File
@@ -1 +0,0 @@
from . import ir_qweb
-30
View File
@@ -1,30 +0,0 @@
# Copyright 2016-2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
from odoo import models
from odoo.tools import config
class IrQweb(models.AbstractModel):
_inherit = "ir.qweb"
def _generate_asset_nodes_cache(
self,
bundle,
css=True,
js=True,
debug=False,
async_load=False,
defer_load=False,
lazy_load=False,
media=None,
):
context_for_printing = self.env.context.copy()
if not config["test_enable"]:
context_for_printing["commit_assetsbundle"] = True
return super(
IrQweb, self.with_context(**context_for_printing)
)._generate_asset_nodes(
bundle, css, js, debug, async_load, defer_load, lazy_load, media
)
@@ -1 +0,0 @@
../../../../kwkhtmltopdf_assets
-6
View File
@@ -1,6 +0,0 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
+1 -1
View File
@@ -3,7 +3,7 @@
{
"name": "test base fileurl fields",
"summary": """A module to verify fileurl field.""",
"version": "12.0.1.0.0",
"version": "17.0.1.0.0",
"category": "Tests",
"author": "Camptocamp,Odoo Community Association (OCA)",
"website": "https://github.com/camptocamp/odoo-cloud-platform",