Add a cloud_platform 'profile' addon

* When installed, it pulls the addons required for Odoo to run on the
  Cloud Platform.
* It provides a method to configure Odoo at the installation.
* It checks if the environment variables are correct according the the
  'server environment'
* And add documentation
This commit is contained in:
Guewen Baconnier
2016-10-25 09:38:48 +02:00
parent 63daa99cdd
commit 982285b298
7 changed files with 260 additions and 3 deletions
+93 -3
View File
@@ -1,4 +1,94 @@
Odoo Monitoring
===============
# Cloud Platform
Camptocamp odoo addons for monitoring / usage analysis.
Camptocamp odoo addons used on our Cloud Platform.
## Introduction
On the platform we want to achieve having:
* no data stored on the local filesystem so we can move an instance
between hosts and even have several running front-ends
* metrics read from the logs or sent to Prometheus to monitor the instances
For the storage, we store all the attachments on a object storage such as S3 or a S3 compatible one, and we store the werkzeug sessions on Redis.
For the metrics, we produce logs as json (TODO) that is sent
to ELK and send data to Prometheus/Grafana using statsd.
## Setup
### Python dependencies
Libraries that must be added in ``requirements.txt``:
```
boto==2.42.0
redis==2.10.5
```
### Server Environment
The server environments in `server_environment_files` must be at least:
* `prod`
* `integration`
* `test`
* `dev`
The exact naming is important, because the `cloud_platform` addon rely on these keys to know and check the running environment.
### Attachments in the Object Storage
* prod: stored RW in the object storage
* `AWS_HOST`: depends of the platform
* `AWS_ACCESS_KEY_ID`: depends of the platform
* `AWS_SECRET_ACCESS_KEY`: depends of the platform
* `AWS_BUCKETNAME`: `<client>-odoo-prod`
* integration: stored RO in the production object storage, fallback
on database for the writes
* `AWS_HOST`: depends of the platform
* `AWS_ACCESS_KEY_ID`: depends of the platform
* `AWS_SECRET_ACCESS_KEY`: depends of the platform
* `AWS_BUCKETNAME`: `<client>-odoo-prod` (this is normal, we read only the data)
* `AWS_ATTACHMENT_READONLY`: `1`
* test: attachments are stored in database
Besides, the
* `ir.config_parameter` `ir_attachment.location`: `s3://` (
### Sessions in Redis
* prod:
* `ODOO_SESSION_REDIS`: 1
* `ODOO_SESSION_REDIS_HOST`: depends of the platform
* `ODOO_SESSION_REDIS_PASSWORD`: depends of the platform
* `ODOO_SESSION_REDIS_PREFIX`: `<client>-odoo-prod`
* integration:
* `ODOO_SESSION_REDIS`: 1
* `ODOO_SESSION_REDIS_HOST`: depends of the platform
* `ODOO_SESSION_REDIS_PASSWORD`: depends of the platform
* `ODOO_SESSION_REDIS_PREFIX`: `<client>-odoo-integration`
* test:
* `ODOO_SESSION_REDIS`: 1
* `ODOO_SESSION_REDIS_HOST`: depends of the platform
* `ODOO_SESSION_REDIS_PASSWORD`: depends of the platform
* `ODOO_SESSION_REDIS_PREFIX`: `<client>-odoo-test`
* `ODOO_SESSION_REDIS_EXPIRATION`: `86400` (1 day)
### Automatic Configuration
Calling `ctx.env['cloud.platform'].install_exoscale()` in an
`anthem` song will configure some parameters such as the
`ir_attachment.location` and migrate the existing attachments to the
object storage.
### Startup checks
At loading of the database, the addon will check if the environment variables
for Redis and the object storage are set as expected for the loaded
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`.
+11
View File
@@ -0,0 +1,11 @@
Cloud Platform
==============
Install addons required for the Camptocamp Cloud platform.
* Provide a quick install that we can call at the setup / migration
of a database
* Check if the environment variables are configured correctly according
to the instance's environment (prod, integration, test or dev) to prevent
data corruption between the environments (such as the integration server
writing on the production object storage).
+3
View File
@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import models
+20
View File
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
{'name': 'Cloud Platform',
'summary': 'Addons required for the Camptocamp Cloud Platform',
'version': '9.0.1.0.0',
'author': 'Camptocamp',
'license': 'AGPL-3',
'category': 'Extra Tools',
'depends': [
'attachment_s3',
#'monitoring_log_requests',
'server_environment', # OCA/server-tools
],
'website': 'http://www.camptocamp.com',
'data': [],
'installable': True,
}
+2
View File
@@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
from . import cloud_platform
+127
View File
@@ -0,0 +1,127 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
import logging
import os
import re
from collections import namedtuple
from distutils.util import strtobool
from openerp import api, models, SUPERUSER_ID
from openerp.tools.config import config
_logger = logging.getLogger(__name__)
def is_true(strval):
return bool(strtobool(strval or '0'.lower()))
PlatformConfig = namedtuple(
'PlatformConfig',
'filestore filestore_readonly'
)
class FilestoreKind(object):
db = 'db'
s3 = 's3://' # or compatible s3 object storage
file = 'file'
class CloudPlatform(models.AbstractModel):
_name = 'cloud.platform'
@api.model
def _config_by_server_env(self, environment):
configs = {
'prod': PlatformConfig(filestore=FilestoreKind.s3,
filestore_readonly=False),
'integration': PlatformConfig(filestore=FilestoreKind.s3,
filestore_readonly=True),
'test': PlatformConfig(filestore=FilestoreKind.db,
filestore_readonly=True),
'dev': PlatformConfig(filestore=FilestoreKind.db,
filestore_readonly=True),
}
return configs.get(environment) or configs['dev']
@api.model
def install_exoscale(self):
params = self.env['ir.config_parameter'].sudo()
params.set_param('cloud.platform.kind', 'exoscale')
environment = config['running_env']
configs = self._config_by_server_env(environment)
params.set_param('ir_attachment.location', configs.filestore)
self.check(self.env)
if configs.filestore == FilestoreKind.s3:
self.env['ir.attachment'].sudo().force_storage()
_logger.info('cloud platform configured for exoscale')
@api.model
def _check_s3(self, environment_name):
params = self.env['ir.config_parameter'].sudo()
attachment_readonly = is_true(
os.environ.get('AWS_ATTACHMENT_READONLY')
)
if environment_name in ('prod', 'integration'):
assert os.environ.get('AWS_ACCESS_KEY_ID')
assert os.environ.get('AWS_SECRET_ACCESS_KEY')
assert os.environ.get('AWS_BUCKETNAME')
bucket_name = os.environ['AWS_BUCKETNAME']
assert re.match(r'[a-z]+-odoo-prod', bucket_name), (
"AWS_BUCKETNAME should match '<client>-odoo-prod', "
"we got: '%s'" % (bucket_name,)
)
assert params.get_param('ir_attachment.location') == 's3://'
# on the integration, we read the filestore from the production
# s3, but we must be readonly!
if environment_name == 'integration':
assert attachment_readonly
else:
assert not attachment_readonly
elif environment_name == 'test':
assert params.get_param('ir_attachment.location') == 'db'
else:
assert params.get_param('ir_attachment.location') in ('db', 'file')
@api.model
def _check_redis(self, environment_name):
assert is_true(os.environ.get('ODOO_SESSION_REDIS'))
assert os.environ.get('ODOO_SESSION_REDIS_HOST')
assert os.environ.get('ODOO_SESSION_REDIS_PREFIX')
prefix = os.environ['ODOO_SESSION_REDIS_PREFIX']
if environment_name in ('prod', 'integration', 'test'):
assert re.match(r'[a-z]+-odoo-%s' % (environment_name,), prefix), (
"ODOO_SESSION_REDIS_PREFIX should match '<client>-odoo-%s', "
"we got: '%s'" % (environment_name, prefix)
)
@api.model
def check(self):
if is_true(os.environ.get('ODOO_CLOUD_PLATFORM_UNSAFE')):
_logger.warning(
"cloud platform checks disabled, this is not safe"
)
return
params = self.env['ir.config_parameter'].sudo()
kind = params.get_param('cloud.platform.kind')
if not kind:
_logger.warning(
"cloud platform not configured, you should "
"probably run 'env['cloud.platform'].install_exoscale()'"
)
return
environment_name = config['running_env']
self._check_s3(environment_name)
self._check_redis(environment_name)
@api.cr
def _register_hook(self, cr):
env = api.Environment(cr, SUPERUSER_ID, {})
env['cloud.platform'].check()
+4
View File
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
def install_exoscale(ctx):
ctx.env['cloud.platform'].install_exoscale()