From ef3018e414bbb16e71a4bfbf81da051978366506 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20-=20Le=20Filament?= <remi@le-filament.com> Date: Wed, 5 Jul 2023 11:34:32 +0200 Subject: [PATCH] [UPD] ansible-linter and update default vars + README --- .ansible-lint | 7 + .yamllint | 39 +++++ README.md | 24 +-- defaults/main.yml | 112 ------------ files/openssl.cnf | 359 ------------------------------------- handlers/main.yml | 84 ++++----- meta/main.yml | 32 ++-- tasks/instance.yml | 428 ++++++++++++++++++++++----------------------- tasks/main.yml | 90 +++++----- 9 files changed, 369 insertions(+), 806 deletions(-) create mode 100644 .ansible-lint create mode 100644 .yamllint delete mode 100644 files/openssl.cnf diff --git a/.ansible-lint b/.ansible-lint new file mode 100644 index 0000000..8d40d06 --- /dev/null +++ b/.ansible-lint @@ -0,0 +1,7 @@ +--- +warn_list: # or 'skip_list' to silence them completely + - git-latest # Git checkouts must contain explicit version + - ignore-errors # Use failed_when and specify error conditions instead of using ignore_errors + - no-changed-when # Commands should not change things if nothing needs doing + - no-handler # Tasks that run when changed should likely be handlers + - package-latest # Package installs should not use latest diff --git a/.yamllint b/.yamllint new file mode 100644 index 0000000..fbebdb8 --- /dev/null +++ b/.yamllint @@ -0,0 +1,39 @@ +--- +# Based on ansible-lint config +extends: default + +rules: + braces: + max-spaces-inside: 1 + level: error + brackets: + max-spaces-inside: 1 + level: error + colons: + max-spaces-after: -1 + level: error + commas: + max-spaces-after: -1 + level: error + # comments enable + comments: enable + comments-indentation: enable + document-start: enable + empty-lines: + max: 3 + level: error + hyphens: + level: error + indentation: + level: warning + indent-sequences: consistent + spaces: 4 + check-multi-line-strings: true + key-duplicates: enable + line-length: disable + new-line-at-end-of-file: enable + new-lines: + type: unix + # trailing-spaces enable + trailing-spaces: enable + truthy: enable diff --git a/README.md b/README.md index 7f4a5a9..3c798bf 100644 --- a/README.md +++ b/README.md @@ -2,18 +2,16 @@ docker_odoo =========== This role deploys Odoo (community edition) in a Docker, together with PostgreSQL, postfix proxy, metabase, etc. as needed -By default, this role would deploy : -* 1 production instance -* 1 test instance -with the following workflow : +By default, this role would deploy as many instances as defined in odoo_instances variable. +Usually we deploy for each of our customers 2 instance (prod and test) with the following workflow : 1. Build Odoo image on test instance 2. Test image on test instance 3. Once confirmed OK, copy test image in prod image and restart prod instance on this new image 4. Use prod image on production instance -This role is originally derivated from the work done by [Tecnativa/Doodba](https://github.com/Tecnativa/doodba) for creating a generic Odoo Docker, although it has been reworked lately in order to reduce drastically the size of the Docker image used, since using Tecnativa Doodba, we were reaching 1.5 GB for the image, when the new images are around 800 MB. +This role is originally derivated from the work done by [Tecnativa/Doodba](https://github.com/Tecnativa/doodba) for creating a generic Odoo Docker, although it has been reworked lately in order to reduce drastically the size of the Docker image used, since using Tecnativa Doodba, we were reaching 1.5 GB for the image, when the new images are around 1 GB. -This role is taking advantage of [Le Filament Odoo Docker](https://hub.docker.com/repository/docker/lefilament/odoo) which is also described on corresponding [Le Filament GitHub page](https://github.com/lefilament/odoo_docker) and adds on top additional OCA modules and private modules defined with variables *odoo_custom_modules_oca* and *odoo_custom_modules* (see below) +This role is taking advantage of [Le Filament Odoo Docker image](https://hub.docker.com/repository/docker/lefilament/odoo) which is also described on (and built from) [Le Filament GitLab page](https://sources.le-filament.com/lefilament/odoo_docker) and adds on top additional OCA modules and private modules that are used by most of our customers. Requirements @@ -131,18 +129,15 @@ odoo_instances: * whitelisted_urls : this list may contain URLs that would be accessible from prod and nonprod Odoo instances * extra_urls defined in either odoo_prod or any odoo_nonprod_instances may contain URLs that would be accessible only from the instance in which it is defined (as an example, with this variable you would be able to allow access to some API only for prod instance) -* Mail server : by default, nonprod instances are not allowed to communicate towards mail server and are connected to a [mailhog]() instance allowing to check what e-mails would have been sent out. This would allow again to have only prod instance being able to send e-mails to partners. The following variables can be used to authorize access to mail server (SMTP/IMAP) and to configure local postfix relay (this way you would not need to configure e-mail server credentials in Odoo database) : +* Mail server : by default, nonprod instances are not allowed to communicate towards mail server and are connected to a [mailhog](https://github.com/mailhog/MailHog) instance allowing to check what e-mails would have been sent out. This would allow again to have only prod instance being able to send e-mails to partners. The following variables can be used to authorize access to mail server (SMTP/IMAP) and to configure local postfix relay (this way you would not need to configure e-mail server credentials in Odoo database) : * mailname : if defined (together with the mailserver and smtp** variables) a postfix local relay will be deployed and used by prod instance only. If not defined, a mailhog instance would be deployed on prod also. * imap_mailserver : if defined a whitelist is created to allow connecting to IMAP server on port 993 (see also the previous section related to Internet Access for explaining why these whitelists might be required) -* Bank : some variables may be defined to deploy [woob](https://woob.tech/) on the server together with configuration of bank accounts. This would allow to web scrap your bank website to collect daily bank statements that can then be automatically imported in Odoo prod instance. - - * Backups (for backups to be deployed, host needs to be in maintenance_contract group) : the backups make use of [Tecnativa Duplicity Docker](https://github.com/Tecnativa/docker-duplicity) * swift_accounts dict parameters for object storage instances where backups should be pushed daily * odoo_backup_pass : Passphrase for encryption of backups -* Metabase : This role allows for deployment of Metabase, a Business Intelligence (BI) Open Source tool that would be connected with readonly used on prod database in order to extract metrics and indicators from Odoo database and display those in dashboards. +* Metabase : This role allows for deployment of [Metabase](https://www.metabase.com/), a Business Intelligence (BI) Open Source tool that would be connected with readonly used on prod database in order to extract metrics and indicators from Odoo database and display those in dashboards. Dependencies @@ -159,13 +154,6 @@ Example Playbook Given the number of variables (see defaults/main.yml), it would be preferable to create a host_vars file listing all the variables needed for you Odoo server, rather than giving your variables through the playbook directly. -Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: - - - hosts: servers - roles: - - { role: docker_odoo } - vars: - - { odoo_version: 14 } License ------- diff --git a/defaults/main.yml b/defaults/main.yml index 28eab5e..3783b4b 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -8,122 +8,10 @@ custom_modules_base_url: "https://sources.le-filament.com/lefilament" ## OPTIONAL - Default configuration to use namespaces (set to false to not use namespace) docker_userns_remap: true -## OPTIONAL - Odoo multilingual - Will install Odoo with all languages (English and French only if set to no - by default) - uncomment and set to yes if needed -odoo_multilingual: false - -## OPTIONAL - Force usage of Python 3.6 for Odoo 12.0 -odoo_python36: false - -## OPTIONAL - Extra pip packages to be installed in image -# odoo_pip_packages: unidecode - -### OPTIONAL - Mail server configuration - for Odoo - uncomment to add mail server -## Mail domain -# mailname: example.org -## Mail server -# mailserver: smtp.example.org -## SMTP port -# smtpport: 465 -## SMTP user -# smtpuser: smtpuser -## SMTP password -# smtppass: veryUnsecurePassToBeModified -## IMAP mail server -# imap_mailserver: imap.example.org - -## OPTIONAL - Bank configuration - for Odoo automatic retrieval of statements (based on https://woob.tech/) -## Should auto retrieval be activated ? -banking: false -## Bank name -# bank: "caissedepargne" -## Bank website (if required by woob) -# bank_website: "www.caisse-epargne.fr" -## Bank user -# bank_login: "12345677890" -## Bank user id (if required by your bank) -# bank_userid: "0001" -## Bank password -# bank_pass: "123456" -## Bank account -# bank_account: "bankaccount1" -## Bank account 2 -# bank_account: "bankaccount2" -## Bank account 3 -# bank_account: "bankaccount3" -## This role allows for defining up to 3 accounts for this bank, but also a second bank and 2 accounts with the following variables : -# bank_account2: "bankaccount2" -# bank_account3: "bankaccount3" -# bank2: "cragr" -# bank2_login: "12345677890" -# bank2_pass: "123456" -# bank2_userid: "0001" -# bank2_account: "bank2account1" -# bank2_account: "bank2account2" - -## OPTIONAL - GIT private keys - for retrieving private repos (outside Le Filament ones) - uncomment and provide keys as needed -# git_private_keys: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK0wmN/Cr3JXqmLW7u+g9pTh+wyqDHpSQEIQczXkVx9q testuser" - # whether dockers should be granted access to Internet or if networks are internal only # (defaults to true meaning docker containers have no direct internet access, # whitelisted URLs should be used to grant specific access) restrict_internet_access: true -## OPTIONAL - Whitelisted URLs allowed to be reached from Odoo SERVER -# whitelisted_urls: -# - accounts.google.com -# - cdnjs.cloudflare.com -# - www.google.com -# - www.googleapis.com -# - www.gravatar.com -# - nominatim.openstreetmap.org -# - data.opendatasoft.com -# - github.com -# - bitbucket.org -# - sources.le-filament.com -# - fonts.googleapis.com -# - fonts.gstatic.com ## OPTIONAL - Allow access to Odoo DB from outside world odoo_remote_db_access: false -## OPTIONAL - Extra commands to be added in Dockerfile building Odoo image -# odoo_specific_dockerfile_commands: [] -## OPTIONAL - Extra host to be defined in Odoo docker /etc/hosts for local access and prevent DNS resolution -# odoo_extra_host: "docs.example.org:172.17.0.1" -## OPTIONAL - update performance limits for Odoo (see https://www.odoo.com/documentation/14.0/developer/reference/cmdline.html) -# odoo_db_maxconn: 64 -# odoo_limit_time_cpu: 300 -# odoo_limit_time_real: 600 -## OPTIONAL - Extra variables to be added in odoo.conf -# odoo_server_wide_modules: "queue_job" -# modules_auto_install_disabled: "stock_sms" -# modules_auto_install_enabled: "mail_tracking" -# odoo_extra_conf: "log_level = debug" -## OPTIONAL - update performance limits for Odoo (see https://www.odoo.com/documentation/14.0/developer/reference/cmdline.html) -# postgres_options: "-c max_connections=100" - -## OPTIONAL - Deploy Metabase -metabase: false -# metabase_db_ro_user: readonlyuser -# metabase_db_ro_pass: veryUnsecurePassToBeModified - - -## OPTIONAL - For Backups only -# swift_accounts: -## Parameters for pushing backups to Object Storage - Instance 1 -# - authurl: https://auth.cloud.ovh.net/v3/ -# authversion: 3 -# tenantid: "132e1fa" -# tenantname: "12312534534" -# username: "testuser" -# password: "testpassword" -# regionname: "GRA" -# -## Parameters for pushing backups to Object Storage - Instance 2 -# - authurl: https://auth.cloud.ovh.net/v3/ -# authversion: 3 -# tenantid: "12323534ab" -# tenantname: "123124235345" -# username: "testuser" -# password: "testpassword" -# regionname: "DE" -## Passphrase for backups encryption -# odoo_backup_pass: notSecureEnoughPasswordToBeModified diff --git a/files/openssl.cnf b/files/openssl.cnf deleted file mode 100644 index 5506bbd..0000000 --- a/files/openssl.cnf +++ /dev/null @@ -1,359 +0,0 @@ -openssl_conf = openssl_init -# -# OpenSSL example configuration file. -# This is mostly being used for generation of certificate requests. -# - -# Note that you can include other files from the main configuration -# file using the .include directive. -#.include filename - -# This definition stops the following lines choking if HOME isn't -# defined. -HOME = . - -# Extra OBJECT IDENTIFIER info: -#oid_file = $ENV::HOME/.oid -oid_section = new_oids - -# To use this configuration file with the "-extfile" option of the -# "openssl x509" utility, name here the section containing the -# X.509v3 extensions to use: -# extensions = -# (Alternatively, use a configuration file that has only -# X.509v3 extensions in its main [= default] section.) - -[ new_oids ] - -# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. -# Add a simple OID like this: -# testoid1=1.2.3.4 -# Or use config file substitution like this: -# testoid2=${testoid1}.5.6 - -# Policies used by the TSA examples. -tsa_policy1 = 1.2.3.4.1 -tsa_policy2 = 1.2.3.4.5.6 -tsa_policy3 = 1.2.3.4.5.7 - -#################################################################### -[ ca ] -default_ca = CA_default # The default ca section - -#################################################################### -[ CA_default ] - -dir = ./demoCA # Where everything is kept -certs = $dir/certs # Where the issued certs are kept -crl_dir = $dir/crl # Where the issued crl are kept -database = $dir/index.txt # database index file. -#unique_subject = no # Set to 'no' to allow creation of - # several certs with same subject. -new_certs_dir = $dir/newcerts # default place for new certs. - -certificate = $dir/cacert.pem # The CA certificate -serial = $dir/serial # The current serial number -crlnumber = $dir/crlnumber # the current crl number - # must be commented out to leave a V1 CRL -crl = $dir/crl.pem # The current CRL -private_key = $dir/private/cakey.pem# The private key - -x509_extensions = usr_cert # The extensions to add to the cert - -# Comment out the following two lines for the "traditional" -# (and highly broken) format. -name_opt = ca_default # Subject Name options -cert_opt = ca_default # Certificate field options - -# Extension copying option: use with caution. -# copy_extensions = copy - -# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs -# so this is commented out by default to leave a V1 CRL. -# crlnumber must also be commented out to leave a V1 CRL. -# crl_extensions = crl_ext - -default_days = 365 # how long to certify for -default_crl_days= 30 # how long before next CRL -default_md = default # use public key default MD -preserve = no # keep passed DN ordering - -# A few difference way of specifying how similar the request should look -# For type CA, the listed attributes must be the same, and the optional -# and supplied fields are just that :-) -policy = policy_match - -# For the CA policy -[ policy_match ] -countryName = match -stateOrProvinceName = match -organizationName = match -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -# For the 'anything' policy -# At this point in time, you must list all acceptable 'object' -# types. -[ policy_anything ] -countryName = optional -stateOrProvinceName = optional -localityName = optional -organizationName = optional -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -#################################################################### -[ req ] -default_bits = 2048 -default_keyfile = privkey.pem -distinguished_name = req_distinguished_name -attributes = req_attributes -x509_extensions = v3_ca # The extensions to add to the self signed cert - -# Passwords for private keys if not present they will be prompted for -# input_password = secret -# output_password = secret - -# This sets a mask for permitted string types. There are several options. -# default: PrintableString, T61String, BMPString. -# pkix : PrintableString, BMPString (PKIX recommendation before 2004) -# utf8only: only UTF8Strings (PKIX recommendation after 2004). -# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). -# MASK:XXXX a literal mask value. -# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. -string_mask = utf8only - -# req_extensions = v3_req # The extensions to add to a certificate request - -[ req_distinguished_name ] -countryName = Country Name (2 letter code) -countryName_default = AU -countryName_min = 2 -countryName_max = 2 - -stateOrProvinceName = State or Province Name (full name) -stateOrProvinceName_default = Some-State - -localityName = Locality Name (eg, city) - -0.organizationName = Organization Name (eg, company) -0.organizationName_default = Internet Widgits Pty Ltd - -# we can do this but it is not needed normally :-) -#1.organizationName = Second Organization Name (eg, company) -#1.organizationName_default = World Wide Web Pty Ltd - -organizationalUnitName = Organizational Unit Name (eg, section) -#organizationalUnitName_default = - -commonName = Common Name (e.g. server FQDN or YOUR name) -commonName_max = 64 - -emailAddress = Email Address -emailAddress_max = 64 - -# SET-ex3 = SET extension number 3 - -[ req_attributes ] -challengePassword = A challenge password -challengePassword_min = 4 -challengePassword_max = 20 - -unstructuredName = An optional company name - -[ usr_cert ] - -# These extensions are added when 'ca' signs a request. - -# This goes against PKIX guidelines but some CAs do it and some software -# requires this to avoid interpreting an end user certificate as a CA. - -basicConstraints=CA:FALSE - -# Here are some examples of the usage of nsCertType. If it is omitted -# the certificate can be used for anything *except* object signing. - -# This is OK for an SSL server. -# nsCertType = server - -# For an object signing certificate this would be used. -# nsCertType = objsign - -# For normal client use this is typical -# nsCertType = client, email - -# and for everything including object signing: -# nsCertType = client, email, objsign - -# This is typical in keyUsage for a client certificate. -# keyUsage = nonRepudiation, digitalSignature, keyEncipherment - -# This will be displayed in Netscape's comment listbox. -nsComment = "OpenSSL Generated Certificate" - -# PKIX recommendations harmless if included in all certificates. -subjectKeyIdentifier=hash -authorityKeyIdentifier=keyid,issuer - -# This stuff is for subjectAltName and issuerAltname. -# Import the email address. -# subjectAltName=email:copy -# An alternative to produce certificates that aren't -# deprecated according to PKIX. -# subjectAltName=email:move - -# Copy subject details -# issuerAltName=issuer:copy - -#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem -#nsBaseUrl -#nsRevocationUrl -#nsRenewalUrl -#nsCaPolicyUrl -#nsSslServerName - -# This is required for TSA certificates. -# extendedKeyUsage = critical,timeStamping - -[ v3_req ] - -# Extensions to add to a certificate request - -basicConstraints = CA:FALSE -keyUsage = nonRepudiation, digitalSignature, keyEncipherment - -[ v3_ca ] - - -# Extensions for a typical CA - - -# PKIX recommendation. - -subjectKeyIdentifier=hash - -authorityKeyIdentifier=keyid:always,issuer - -basicConstraints = critical,CA:true - -# Key usage: this is typical for a CA certificate. However since it will -# prevent it being used as an test self-signed certificate it is best -# left out by default. -# keyUsage = cRLSign, keyCertSign - -# Some might want this also -# nsCertType = sslCA, emailCA - -# Include email address in subject alt name: another PKIX recommendation -# subjectAltName=email:copy -# Copy issuer details -# issuerAltName=issuer:copy - -# DER hex encoding of an extension: beware experts only! -# obj=DER:02:03 -# Where 'obj' is a standard or added object -# You can even override a supported extension: -# basicConstraints= critical, DER:30:03:01:01:FF - -[ crl_ext ] - -# CRL extensions. -# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. - -# issuerAltName=issuer:copy -authorityKeyIdentifier=keyid:always - -[ proxy_cert_ext ] -# These extensions should be added when creating a proxy certificate - -# This goes against PKIX guidelines but some CAs do it and some software -# requires this to avoid interpreting an end user certificate as a CA. - -basicConstraints=CA:FALSE - -# Here are some examples of the usage of nsCertType. If it is omitted -# the certificate can be used for anything *except* object signing. - -# This is OK for an SSL server. -# nsCertType = server - -# For an object signing certificate this would be used. -# nsCertType = objsign - -# For normal client use this is typical -# nsCertType = client, email - -# and for everything including object signing: -# nsCertType = client, email, objsign - -# This is typical in keyUsage for a client certificate. -# keyUsage = nonRepudiation, digitalSignature, keyEncipherment - -# This will be displayed in Netscape's comment listbox. -nsComment = "OpenSSL Generated Certificate" - -# PKIX recommendations harmless if included in all certificates. -subjectKeyIdentifier=hash -authorityKeyIdentifier=keyid,issuer - -# This stuff is for subjectAltName and issuerAltname. -# Import the email address. -# subjectAltName=email:copy -# An alternative to produce certificates that aren't -# deprecated according to PKIX. -# subjectAltName=email:move - -# Copy subject details -# issuerAltName=issuer:copy - -#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem -#nsBaseUrl -#nsRevocationUrl -#nsRenewalUrl -#nsCaPolicyUrl -#nsSslServerName - -# This really needs to be in place for it to be a proxy certificate. -proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo - -#################################################################### -[ tsa ] - -default_tsa = tsa_config1 # the default TSA section - -[ tsa_config1 ] - -# These are used by the TSA reply generation only. -dir = ./demoCA # TSA root directory -serial = $dir/tsaserial # The current serial number (mandatory) -crypto_device = builtin # OpenSSL engine to use for signing -signer_cert = $dir/tsacert.pem # The TSA signing certificate - # (optional) -certs = $dir/cacert.pem # Certificate chain to include in reply - # (optional) -signer_key = $dir/private/tsakey.pem # The TSA private key (optional) -signer_digest = sha256 # Signing digest to use. (Optional) -default_policy = tsa_policy1 # Policy if request did not specify it - # (optional) -other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) -digests = sha1, sha256, sha384, sha512 # Acceptable message digests (mandatory) -accuracy = secs:1, millisecs:500, microsecs:100 # (optional) -clock_precision_digits = 0 # number of digits after dot. (optional) -ordering = yes # Is ordering defined for timestamps? - # (optional, default: no) -tsa_name = yes # Must the TSA name be included in the reply? - # (optional, default: no) -ess_cert_id_chain = no # Must the ESS cert id chain be included? - # (optional, default: no) -ess_cert_id_alg = sha1 # algorithm to compute certificate - # identifier (optional, default: sha1) -[openssl_init] -ssl_conf = ssl_sect - -[ssl_sect] -system_default = system_default_sect - -[system_default_sect] -CipherString = DEFAULT@SECLEVEL=1 diff --git a/handlers/main.yml b/handlers/main.yml index 9c8acb0..242871a 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -1,59 +1,59 @@ --- -- name: start odoo whitelists - docker_compose: - project_src: /home/docker - files: whitelists.yaml - project_name: whitelists +- name: Start odoo whitelists + community.docker.docker_compose: + project_src: /home/docker + files: whitelists.yaml + project_name: whitelists -- name: pull odoo ML image - docker_image: - name: lefilament/odoo:{{ instance_odoo_version }}_ml - source: pull - force_source: true +- name: Pull odoo ML image + community.docker.docker_image: + name: lefilament/odoo:{{ instance_odoo_version }}_ml + source: pull + force_source: true when: not ansible_check_mode and instance.value.odoo_multilingual | default(false) -- name: pull odoo Python3.6 image - docker_image: - name: lefilament/odoo:{{ instance_odoo_version }}_py3.6 - source: pull - force_source: true +- name: Pull odoo Python3.6 image + community.docker.docker_image: + name: lefilament/odoo:{{ instance_odoo_version }}_py3.6 + source: pull + force_source: true when: not ansible_check_mode and instance.value.odoo_python36 | default(false) -- name: pull odoo image - docker_image: - name: lefilament/odoo:{{ instance_odoo_version }} - source: pull - force_source: true +- name: Pull odoo image + community.docker.docker_image: + name: lefilament/odoo:{{ instance_odoo_version }} + source: pull + force_source: true when: not ansible_check_mode and not (instance.value.odoo_multilingual | default(false) or instance.value.odoo_python36 | default(false)) -- name: build odoo image - docker_compose: - project_src: /home/docker/{{ instance.key }}/ - build: true - nocache: true - recreate: always - restarted: true - remove_orphans: true +- name: Build odoo image + community.docker.docker_compose: + project_src: /home/docker/{{ instance.key }}/ + build: true + nocache: true + recreate: always + restarted: true + remove_orphans: true async: 600 poll: 10 when: not ansible_check_mode -- name: start odoo container - docker_compose: - project_src: /home/docker/{{ instance.key }}/ - remove_orphans: true +- name: Start odoo container + community.docker.docker_compose: + project_src: /home/docker/{{ instance.key }}/ + remove_orphans: true when: not ansible_check_mode -- name: remove intermediate image - docker_prune: - builder_cache: true - images: true - images_filters: - label: stage=builder +- name: Remove intermediate image + community.docker.docker_prune: + builder_cache: true + images: true + images_filters: + label: stage=builder when: not ansible_check_mode and inventory_hostname not in groups['maintenance_contract'] -- name: remove ssh private keys - file: - path: "/home/docker/{{ instance.key }}/odoo/id_ed25519.sources" - state: absent +- name: Remove ssh private keys + ansible.builtin.file: + path: "/home/docker/{{ instance.key }}/odoo/id_ed25519.sources" + state: absent when: not ansible_check_mode and inventory_hostname not in groups['maintenance_contract'] diff --git a/meta/main.yml b/meta/main.yml index 86569db..1767721 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -1,18 +1,18 @@ --- galaxy_info: - author: Rémi - description: Role for deploying Odoo Community Edition on Docker - company: Le Filament (https://le-filament.com) - license: AGPL-3.0-or-later - min_ansible_version: 2.1 - platforms: - - name: Ubuntu - versions: - - bionic - - focal - galaxy_tags: - - odoo - - community - - docker - - metabase - - postgresql + author: lefilament + description: Role for deploying Odoo Community Edition on Docker + company: Le Filament (https://le-filament.com) + license: AGPL-3.0-or-later + min_ansible_version: "2.1" + platforms: + - name: Ubuntu + versions: + - bionic + - focal + galaxy_tags: + - odoo + - community + - docker + - metabase + - postgresql diff --git a/tasks/instance.yml b/tasks/instance.yml index 59f1d7f..cd7d896 100644 --- a/tasks/instance.yml +++ b/tasks/instance.yml @@ -1,136 +1,136 @@ --- -- name: create Odoo docker structure on server in /home/docker/{{ item.key }} - file: - name: "/home/docker/{{ item.key }}" - state: directory - owner: root - group: root - mode: '0755' - -- name: container building requirements +- name: Create Odoo docker structure on server in /home/docker/{{ item.key }} + ansible.builtin.file: + name: "/home/docker/{{ item.key }}" + state: directory + owner: root + group: root + mode: '0755' + +- name: Container building requirements when: item.value.image_instance | default(false) == item.key tags: ['never', 'build_odoo'] block: - - name: create Odoo docker structure on server in /home/docker/{{ item.key }}/odoo/private - file: - name: "/home/docker/{{ item.key }}/odoo/private" - state: directory - owner: root - group: root - mode: '0755' - - - name: copy update scripts to be run during build - template: - src: "{{ file }}" - dest: "/home/docker/{{ item.key }}/odoo/private/" - owner: root - group: root - mode: '0750' - with_items: - - fetch_repos - - fetch_repos_addons - loop_control: - loop_var: file - notify: - - pull odoo ML image - - pull odoo Python3.6 image - - pull odoo image - - build odoo image - - - name: set repos variables from template - template: - src: "{{ file }}.j2" - dest: "/home/docker/{{ item.key }}/odoo/private/{{ file }}" - owner: root - group: root - mode: '0644' - with_items: - - "repos.yaml" - - "repos-addons.yaml" - loop_control: - loop_var: file - notify: - - pull odoo ML image - - pull odoo Python3.6 image - - pull odoo image - - build odoo image - - - name: copy odoo.conf file - template: - src: odoo.conf.j2 - dest: "/home/docker/{{ item.key }}/odoo/odoo.conf" - owner: root - group: root - mode: '0600' - notify: build odoo image - - - name: copy private GitLab ssh keys file - copy: - content: "{{ git_modules_privkey | default('') }}" - dest: "/home/docker/{{ item.key }}/odoo/id_ed25519.sources" - owner: root - group: root - mode: '0400' - notify: - - build odoo image - - remove ssh private keys - - remove intermediate image - - - name: copy ssh config for connecting to LF Gitlab - copy: - src: ssh_config - dest: "/home/docker/{{ item.key }}/odoo/ssh_config" - owner: root - group: root - mode: '0444' - notify: build odoo image - - - name: copy private Git ssh keys file - when: git_private_keys | default(false) - copy: - content: "{{ git_private_keys }}" - dest: "/home/docker/{{ item.key }}/odoo/id_rsa" - owner: root - group: root - mode: '0400' - notify: build odoo image - - - name: copy Dockerfile to retrieve private repos and extra OCA ones - template: - src: Dockerfile.j2 - dest: "/home/docker/{{ item.key }}/odoo/Dockerfile" - owner: root - group: root - mode: '0644' - notify: - - pull odoo ML image - - pull odoo Python3.6 image - - pull odoo image - - build odoo image + - name: Create Odoo private docker structure on server in /home/docker/{{ item.key }} + ansible.builtin.file: + name: "/home/docker/{{ item.key }}/odoo/private" + state: directory + owner: root + group: root + mode: '0755' + + - name: Copy update scripts to be run during build + ansible.builtin.template: + src: "{{ file }}" + dest: "/home/docker/{{ item.key }}/odoo/private/" + owner: root + group: root + mode: '0750' + with_items: + - fetch_repos + - fetch_repos_addons + loop_control: + loop_var: file + notify: + - Pull odoo ML image + - Pull odoo Python3.6 image + - Pull odoo image + - Build odoo image + + - name: Set repos variables from template + ansible.builtin.template: + src: "{{ file }}.j2" + dest: "/home/docker/{{ item.key }}/odoo/private/{{ file }}" + owner: root + group: root + mode: '0644' + with_items: + - "repos.yaml" + - "repos-addons.yaml" + loop_control: + loop_var: file + notify: + - Pull odoo ML image + - Pull odoo Python3.6 image + - Pull odoo image + - Build odoo image + + - name: Copy odoo.conf file + ansible.builtin.template: + src: odoo.conf.j2 + dest: "/home/docker/{{ item.key }}/odoo/odoo.conf" + owner: root + group: root + mode: '0600' + notify: Build odoo image + + - name: Copy private GitLab ssh keys file + ansible.builtin.copy: + content: "{{ git_modules_privkey | default('') }}" + dest: "/home/docker/{{ item.key }}/odoo/id_ed25519.sources" + owner: root + group: root + mode: '0400' + notify: + - Build odoo image + - Remove ssh private keys + - Remove intermediate image + + - name: Copy ssh config for connecting to LF Gitlab + ansible.builtin.copy: + src: ssh_config + dest: "/home/docker/{{ item.key }}/odoo/ssh_config" + owner: root + group: root + mode: '0444' + notify: Build odoo image + + - name: Copy private Git ssh keys file + when: git_private_keys | default(false) + ansible.builtin.copy: + content: "{{ git_private_keys }}" + dest: "/home/docker/{{ item.key }}/odoo/id_rsa" + owner: root + group: root + mode: '0400' + notify: Build odoo image + + - name: Copy Dockerfile to retrieve private repos and extra OCA ones + ansible.builtin.template: + src: Dockerfile.j2 + dest: "/home/docker/{{ item.key }}/odoo/Dockerfile" + owner: root + group: root + mode: '0644' + notify: + - Pull odoo ML image + - Pull odoo Python3.6 image + - Pull odoo image + - Build odoo image - name: Get image from another instance when: item.value.image_instance | default(false) != item.key block: - - name: Check if instance image exists - docker_image_info: - name: "filament/{{ item.key }}:{{ instance_odoo_setup.odoo_version }}" - register: prod_image - - - name: Copy image from image_instance if it does not exist - when: prod_image.images | length == 0 - docker_image: - name: "filament/{{ item.value.image_instance }}:{{ instance_odoo_setup.odoo_version }}" - repository: "filament/{{ item.key }}:{{ instance_odoo_setup.odoo_version }}" - source: local + - name: Check if instance image exists + community.docker.docker_image_info: + name: "filament/{{ item.key }}:{{ instance_odoo_setup.odoo_version }}" + register: prod_image + + - name: Copy image from image_instance if it does not exist + when: prod_image.images | length == 0 + community.docker.docker_image: + name: "filament/{{ item.value.image_instance }}:{{ instance_odoo_setup.odoo_version }}" + repository: "filament/{{ item.key }}:{{ instance_odoo_setup.odoo_version }}" + source: local - name: Copy docker compose service - template: - src: docker-compose.yaml.j2 - dest: "/home/docker/{{ item.key }}/docker-compose.yml" - owner: root - group: root - mode: '0400' - notify: start odoo container + ansible.builtin.template: + src: docker-compose.yaml.j2 + dest: "/home/docker/{{ item.key }}/docker-compose.yml" + owner: root + group: root + mode: '0400' + notify: Start odoo container # -------------------------------------------------- # non-prod restore section @@ -139,34 +139,34 @@ when: (item.value.backup_instance | default(item.key) != item.key or item.value.backup_host | default(inventory_hostname) != inventory_hostname) and inventory_hostname in groups.maintenance_contract tags: 'backup_odoo' block: - - name: Copy sql script to be run before restoring db from backup_instance - template: - src: pre_restore-odootest.sql.j2 - dest: "/home/docker/backups/pre_restore-{{ item.key }}.sql" - owner: root - group: root - mode: '0444' - - - name: Copy sql script to be run after restoring db from backup_instance - template: - src: post_restore-odootest.sql.j2 - dest: "/home/docker/backups/post_restore-{{ item.key }}.sql" - owner: root - group: root - mode: '0444' - - - name: Copy compose file to restore db from backup_instance - template: - src: restore-odootest.yaml.j2 - dest: "/home/docker/backups/restore-{{ item.key }}{{ account_index + 1 }}.yaml" - owner: root - group: root - mode: '0400' - loop: "{{ swift_accounts }}" - loop_control: - label: "account {{ account_index + 1 }}" - index_var: account_index - loop_var: account + - name: Copy sql script to be run before restoring db from backup_instance + ansible.builtin.template: + src: pre_restore-odootest.sql.j2 + dest: "/home/docker/backups/pre_restore-{{ item.key }}.sql" + owner: root + group: root + mode: '0444' + + - name: Copy sql script to be run after restoring db from backup_instance + ansible.builtin.template: + src: post_restore-odootest.sql.j2 + dest: "/home/docker/backups/post_restore-{{ item.key }}.sql" + owner: root + group: root + mode: '0444' + + - name: Copy compose file to restore db from backup_instance + ansible.builtin.template: + src: restore-odootest.yaml.j2 + dest: "/home/docker/backups/restore-{{ item.key }}{{ account_index + 1 }}.yaml" + owner: root + group: root + mode: '0400' + loop: "{{ swift_accounts }}" + loop_control: + label: "account {{ account_index + 1 }}" + index_var: account_index + loop_var: account # -------------------------------------------------- # prod backup section @@ -175,41 +175,41 @@ when: item.value.backup_instance | default(false) == item.key and item.value.backup_host | default(inventory_hostname) == inventory_hostname and inventory_hostname in groups.maintenance_contract tags: 'backup_odoo' block: - - name: "Copy docker compose for backup account {{ account_index + 1 }}" - template: - src: backup.yaml.j2 - dest: "/home/docker/backups/backup-{{ item.key }}{{ account_index + 1 }}.yaml" - owner: root - group: root - mode: '0400' - loop: "{{ swift_accounts }}" - loop_control: - label: "account {{ account_index + 1 }}" - index_var: account_index - loop_var: account - - # TODO: duplicate with swift_accounts - - name: "Add cron job to run backup account {{ account_index + 1 }} every day" - cron: - name: "backup {{ item.key }}{{ account_index + 1 }}" - minute: "{{ '%M' | strftime((('1970-01-01 ' + backup_time_start) | to_datetime).timestamp() + ( swift_accounts | length - (account_index + 1)) * ((backup_time_slot_duration | community.general.to_seconds - swift_accounts | length * backup_time_max_duration | community.general.to_seconds) / (swift_accounts | length - 1) + backup_time_max_duration | community.general.to_seconds) | int) }}" - hour: "{{ '%H' | strftime((('1970-01-01 ' + backup_time_start) | to_datetime).timestamp() + ( swift_accounts | length - (account_index + 1)) * ((backup_time_slot_duration | community.general.to_seconds - swift_accounts | length * backup_time_max_duration | community.general.to_seconds) / (swift_accounts | length - 1) + backup_time_max_duration | community.general.to_seconds) | int) }}" - job: "/usr/bin/docker-compose -f /home/docker/backups/backup-{{ item.key }}{{ account_index + 1 }}.yaml run --rm backup_odoo" - loop: "{{ swift_accounts }}" - loop_control: - label: "account {{ account_index + 1 }}" - index_var: account_index - loop_var: account + - name: "Copy docker compose for backup account {{ account_index + 1 }}" + ansible.builtin.template: + src: backup.yaml.j2 + dest: "/home/docker/backups/backup-{{ item.key }}{{ account_index + 1 }}.yaml" + owner: root + group: root + mode: '0400' + loop: "{{ swift_accounts }}" + loop_control: + label: "account {{ account_index + 1 }}" + index_var: account_index + loop_var: account + + # TODO: duplicate with swift_accounts + - name: "Add cron job to run every day backup account {{ account_index + 1 }}" + ansible.builtin.cron: + name: "backup {{ item.key }}{{ account_index + 1 }}" + minute: "{{ '%H' | strftime((('1970-01-01 ' + backup_time_start) | to_datetime).timestamp() + (swift_accounts | length - (account_index + 1)) * ((backup_time_slot_duration | community.general.to_seconds - swift_accounts | length * backup_time_max_duration | community.general.to_seconds) / (swift_accounts | length - 1) + backup_time_max_duration | community.general.to_seconds) | int) }}" + hour: "{{ '%H' | strftime((('1970-01-01 ' + backup_time_start) | to_datetime).timestamp() + (swift_accounts | length - (account_index + 1)) * ((backup_time_slot_duration | community.general.to_seconds - swift_accounts | length * backup_time_max_duration | community.general.to_seconds) / (swift_accounts | length - 1) + backup_time_max_duration | community.general.to_seconds) | int) }}" + job: "/usr/bin/docker-compose -f /home/docker/backups/backup-{{ item.key }}{{ account_index + 1 }}.yaml run --rm backup_odoo" + loop: "{{ swift_accounts }}" + loop_control: + label: "account {{ account_index + 1 }}" + index_var: account_index + loop_var: account # Flush handlers. -- name: set facts +- name: Set facts ansible.builtin.set_fact: - instance: "{{ {'key': item.key, 'value': item.value} }}" - instance_odoo_version: "{{ instance_odoo_setup.odoo_version }}" - cacheable: no + instance: "{{ {'key': item.key, 'value': item.value} }}" + instance_odoo_version: "{{ instance_odoo_setup.odoo_version }}" + cacheable: false - name: Flush handlers - meta: flush_handlers + ansible.builtin.meta: flush_handlers # -------------------------------------------------- # Postgres Readonly user @@ -217,36 +217,36 @@ - name: Postgres Read-only user when: item.value.odoo_remote_db_access | default(false) block: - - name: Allow readonly user connection to prod db (with userns_remap) - when: docker_userns_remap - blockinfile: - path: "/var/lib/docker/{{ dockremap_subuid }}.{{ dockremap_subgid }}/volumes/{{ item.key }}_db/_data/pg_hba.conf" - block: | - host {{ item.value.db }} {{ odoo_instances[item.value.prod_instance | default(item.key )].db_user }} 172.16.0.0/12 md5 - host postgres {{ odoo_instances[item.value.prod_instance | default(item.key )].db_user }} 172.16.0.0/12 md5 - host {{ item.value.db }} {{ item.value.odoo_db_rouser }} all md5 - - - name: PROD Allow readonly user connection to prod db (no userns_remap) - when: not docker_userns_remap - blockinfile: - path: /var/lib/docker/volumes/{{ item.key }}_db/_data/pg_hba.conf - block: | - host {{ item.value.db }} {{ odoo_instances[item.value.prod_instance | default(item.key )].db_user }} 172.16.0.0/12 md5 - host postgres {{ odoo_instances[item.value.prod_instance | default(item.key )].db_user }} 172.16.0.0/12 md5 - host {{ item.value.db }} {{ item.value.odoo_db_rouser }} all md5 - - - name: PROD Disable access all rights (with userns_remap) - when: docker_userns_remap - lineinfile: - name: "/var/lib/docker/{{ dockremap_subuid }}.{{ dockremap_subgid }}/volumes/{{ item.key }}_db/_data/pg_hba.conf" - regexp: "^host all all all md5" - line: "#host all all all md5" - - - name: PROD Disable access all rights (no userns_remap) - when: not docker_userns_remap - lineinfile: - name: /var/lib/docker/volumes/{{ item.key }}_db/_data/pg_hba.conf - regexp: "^host all all all md5" - line: "#host all all all md5" - - # TODO: add restart db container + - name: Allow readonly user connection to prod db (with userns_remap) + when: docker_userns_remap + ansible.builtin.blockinfile: + path: "/var/lib/docker/{{ dockremap_subuid }}.{{ dockremap_subgid }}/volumes/{{ item.key }}_db/_data/pg_hba.conf" + block: | + host {{ item.value.db }} {{ odoo_instances[item.value.prod_instance | default(item.key)].db_user }} 172.16.0.0/12 md5 + host postgres {{ odoo_instances[item.value.prod_instance | default(item.key)].db_user }} 172.16.0.0/12 md5 + host {{ item.value.db }} {{ item.value.odoo_db_rouser }} all md5 + + - name: PROD Allow readonly user connection to prod db (no userns_remap) + when: not docker_userns_remap + ansible.builtin.blockinfile: + path: /var/lib/docker/volumes/{{ item.key }}_db/_data/pg_hba.conf + block: | + host {{ item.value.db }} {{ odoo_instances[item.value.prod_instance | default(item.key)].db_user }} 172.16.0.0/12 md5 + host postgres {{ odoo_instances[item.value.prod_instance | default(item.key)].db_user }} 172.16.0.0/12 md5 + host {{ item.value.db }} {{ item.value.odoo_db_rouser }} all md5 + + - name: PROD Disable access all rights (with userns_remap) + when: docker_userns_remap + ansible.builtin.lineinfile: + name: "/var/lib/docker/{{ dockremap_subuid }}.{{ dockremap_subgid }}/volumes/{{ item.key }}_db/_data/pg_hba.conf" + regexp: "^host all all all md5" + line: "#host all all all md5" + + - name: PROD Disable access all rights (no userns_remap) + when: not docker_userns_remap + ansible.builtin.lineinfile: + name: /var/lib/docker/volumes/{{ item.key }}_db/_data/pg_hba.conf + regexp: "^host all all all md5" + line: "#host all all all md5" + +# TODO: add restart db container diff --git a/tasks/main.yml b/tasks/main.yml index e3347ca..3e32ade 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -3,38 +3,38 @@ # Whitelists section # -------------------------------------------------- -- name: copy docker compose for whitelists - template: - src: whitelists.yaml.j2 - dest: "/home/docker/whitelists.yaml" - owner: root - group: root - mode: '0400' - notify: start odoo whitelists +- name: Copy docker compose for whitelists + ansible.builtin.template: + src: whitelists.yaml.j2 + dest: "/home/docker/whitelists.yaml" + owner: root + group: root + mode: '0400' + notify: Start odoo whitelists when: restrict_internet_access and whitelisted_urls | default([]) -- name: non-prod instance setup - include_tasks: - file: instance.yml - apply: - tags: backup_odoo +- name: NON-PROD instance setup + ansible.builtin.include_tasks: + file: instance.yml + apply: + tags: backup_odoo with_dict: "{{ odoo_instances }}" loop_control: - label: "{{ item.key }}" + label: "{{ item.key }}" vars: - instance_odoo_setup: "{{ odoo_setup_conf[item.value.odoo_setup_version | default(odoo_setup_version)] }}" + instance_odoo_setup: "{{ odoo_setup_conf[item.value.odoo_setup_version | default(odoo_setup_version)] }}" when: not (item.value.prod_instance | default(false) == item.key) and (odoo_instance is undefined or item.key == odoo_instance) -- name: prod instance setup - include_tasks: - file: instance.yml - apply: - tags: backup_odoo +- name: PROD instance setup + ansible.builtin.include_tasks: + file: instance.yml + apply: + tags: backup_odoo with_dict: "{{ odoo_instances }}" loop_control: - label: "{{ item.key }}" + label: "{{ item.key }}" vars: - instance_odoo_setup: "{{ odoo_setup_conf[item.value.odoo_setup_version | default(odoo_setup_version)] }}" + instance_odoo_setup: "{{ odoo_setup_conf[item.value.odoo_setup_version | default(odoo_setup_version)] }}" when: item.value.prod_instance | default(false) == item.key and (odoo_instance is undefined or item.key == odoo_instance) # -------------------------------------------------- @@ -42,28 +42,28 @@ # -------------------------------------------------- - name: Remote Imports block: - - name: Push private keys for any external tool connection - when: private_keys is defined - copy: - content: "{{ private_keys }}" - dest: "/root/.ssh/id_rsa" - owner: root - group: root - mode: '0400' + - name: Push private keys for any external tool connection + when: private_keys is defined + ansible.builtin.copy: + content: "{{ private_keys }}" + dest: "/root/.ssh/id_rsa" + owner: root + group: root + mode: '0400' - - name: PROD Copy script file for collecting remote files - when: private_pull is defined - template: - src: pull_remote_files.sh.j2 - dest: /root/pull_remote_files.sh - owner: root - group: root - mode: '0700' + - name: PROD Copy script file for collecting remote files + when: private_pull is defined + ansible.builtin.template: + src: pull_remote_files.sh.j2 + dest: /root/pull_remote_files.sh + owner: root + group: root + mode: '0700' - - name: PROD add cron job to pull files from remote server - when: private_pull is defined - cron: - name: pull remote server files - minute: "30" - hour: "23" - job: /root/pull_remote_files.sh + - name: PROD add cron job to pull files from remote server + when: private_pull is defined + ansible.builtin.cron: + name: pull remote server files + minute: "30" + hour: "23" + job: /root/pull_remote_files.sh -- GitLab