diff --git a/roles/akeneo_pim/defaults/main.yml b/roles/akeneo_pim/defaults/main.yml
new file mode 100644
index 0000000..42aabe0
--- /dev/null
+++ b/roles/akeneo_pim/defaults/main.yml
@@ -0,0 +1,36 @@
+---
+
+# Version to deploy
+pim_version: 5.0.43
+# User under which the PIM will run
+pim_user: php-pim_{{ pim_id }}
+# If you install several pim instance on the same host, you should change the ID for each of them
+pim_id: 1
+# Root directory of the installation
+pim_root_dir: /opt/pim_{{ pim_id }}
+# Should anisble handle upgrades or just initial install
+pim_manage_upgrade: True
+
+# PHP version to use
+pim_php_version: 74
+
+# Database settings
+pim_db_server: "{{ mysql_server | default('localhost') }}"
+pim_db_port: 3306
+pim_db_name: akeneopim_{{ pim_id }}
+pim_db_user: akeneopim_{{ pim_id }}
+# A random pass will be generated and stored in {{ pim_root_dir }}/meta/ansible_dbpass if not defined
+# pim_db_pass: S3cr3t.
+
+# A secret used to sign cookies. A random one will be generated and stored in {{ pim_root_dir }}/meta/ansible_secret if not defined
+# pim_secret: ChangeMe
+
+# Elasticsearch host
+pim_es_server: localhost:9200
+
+# Public URL used to reach AKeneo
+pim_public_url: http://{{ inventory_hostname }}/pim_{{ pim_id }}
+
+# If defined, an alias will be added in httpd's config to access pim
+# Else, you'll have to defined a vhost to make pim accessible. See httpd_common role
+pim_web_alias: /pim_{{ pim_id }}
diff --git a/roles/akeneo_pim/meta/main.yml b/roles/akeneo_pim/meta/main.yml
new file mode 100644
index 0000000..c5eb88a
--- /dev/null
+++ b/roles/akeneo_pim/meta/main.yml
@@ -0,0 +1,12 @@
+---
+
+allow_duplicates: True
+dependencies:
+ - role: mkdir
+ - role: composer
+ - role: mysql_server
+ when: pim_db_server in ['localhost','127.0.0.1']
+ - role: httpd_php
+ - role: nodejs
+ - role: elasticsearch
+ when: pim_es_server | regex_replace('(.*):\d+','\\1') in ['localhost','127.0.0.1']
diff --git a/roles/akeneo_pim/tasks/archive_pre.yml b/roles/akeneo_pim/tasks/archive_pre.yml
new file mode 100644
index 0000000..e1e495f
--- /dev/null
+++ b/roles/akeneo_pim/tasks/archive_pre.yml
@@ -0,0 +1,28 @@
+---
+
+- name: Create the archive dir
+ file: path={{ pim_root_dir }}/archives/{{ pim_current_version }} state=directory
+ tags: pim
+
+- name: Archive current version
+ synchronize:
+ src: "{{ pim_root_dir }}/app"
+ dest: "{{ pim_root_dir }}/archives/{{ pim_current_version }}/"
+ compress: False
+ delete: True
+ delegate_to: "{{ inventory_hostname }}"
+ tags: pim
+
+- name: Dump the database
+ mysql_db:
+ state: dump
+ name: "{{ pim_db_name }}"
+ target: "{{ pim_root_dir }}/archives/{{ pim_current_version }}/{{ pim_db_name }}.sql.xz"
+ login_host: "{{ pim_db_server }}"
+ login_user: "{{ pim_db_user }}"
+ login_password: "{{ pim_db_pass }}"
+ quick: True
+ single_transaction: True
+ environment:
+ XZ_OPT: -T0
+ tags: pim
diff --git a/roles/akeneo_pim/tasks/conf.yml b/roles/akeneo_pim/tasks/conf.yml
new file mode 100644
index 0000000..3906899
--- /dev/null
+++ b/roles/akeneo_pim/tasks/conf.yml
@@ -0,0 +1,32 @@
+---
+
+- name: Deploy configuration
+ template: src=env.j2 dest={{ pim_root_dir }}/app/.env.local group={{ pim_user }} mode=640
+ tags: pim
+
+- import_tasks: ../includes/webapps_webconf.yml
+ vars:
+ - app_id: pim_{{ pim_id }}
+ - php_version: "{{ pim_php_version }}"
+ - php_fpm_pool: "{{ pim_php_fpm_pool | default('') }}"
+ tags: pim
+
+- name: Build assets
+ command: scl enable php{{ pim_php_version }} -- make prod
+ args:
+ chdir: "{{ pim_root_dir }}/app"
+ environment:
+ NO_DOCKER: true
+ become_user: "{{ pim_user }}"
+ when: pim_install_mode != 'none'
+ tags: pim
+
+- name: Deploy permission script
+ template: src=perms.sh.j2 dest={{ pim_root_dir }}/perms.sh mode=755
+ register: pim_perm_script
+ tags: pim
+
+- name: Apply permissions
+ command: "{{ pim_root_dir }}/perms.sh"
+ when: pim_perm_script.changed or pim_install_mode != 'none'
+ tags: pim
diff --git a/roles/akeneo_pim/tasks/directories.yml b/roles/akeneo_pim/tasks/directories.yml
new file mode 100644
index 0000000..b444c78
--- /dev/null
+++ b/roles/akeneo_pim/tasks/directories.yml
@@ -0,0 +1,26 @@
+---
+
+- name: Create nedded directories
+ file: path={{ item.dir }} state=directory owner={{ item.owner | default(omit) }} group={{ item.group | default(omit) }} mode={{ item.mode | default(omit) }}
+ loop:
+ - dir: "{{ pim_root_dir }}/meta"
+ mode: 700
+ - dir: "{{ pim_root_dir }}/archives"
+ mode: 700
+ - dir: "{{ pim_root_dir }}/backup"
+ mode: 700
+ - dir: "{{ pim_root_dir }}/data"
+ owner: "{{ pim_user }}"
+ mode: 700
+ - dir: "{{ pim_root_dir }}/app"
+ owner: "{{ pim_user }}"
+ group: "{{ pim_user }}"
+ - dir: "{{ pim_root_dir }}/tmp"
+ owner: "{{ pim_user }}"
+ group: "{{ pim_user }}"
+ mode: 700
+ - dir: "{{ pim_root_dir }}/sessions"
+ owner: "{{ pim_user }}"
+ group: "{{ pim_user }}"
+ mode: 700
+ tags: pim
diff --git a/roles/akeneo_pim/tasks/facts.yml b/roles/akeneo_pim/tasks/facts.yml
new file mode 100644
index 0000000..7ccefd2
--- /dev/null
+++ b/roles/akeneo_pim/tasks/facts.yml
@@ -0,0 +1,29 @@
+---
+
+# Detect installed version (if any)
+- block:
+ - import_tasks: ../includes/webapps_set_install_mode.yml
+ vars:
+ - root_dir: "{{ pim_root_dir }}"
+ - version: "{{ pim_version }}"
+ - set_fact: pim_install_mode={{ (install_mode == 'upgrade' and not pim_manage_upgrade) | ternary('none',install_mode) }}
+ - set_fact: pim_current_version={{ current_version | default('') }}
+ tags: pim
+
+# Create a random pass for the DB if needed
+- block:
+ - import_tasks: ../includes/get_rand_pass.yml
+ vars:
+ - pass_file: "{{ pim_root_dir }}/meta/ansible_dbpass"
+ - set_fact: pim_db_pass={{ rand_pass }}
+ when: pim_db_pass is not defined
+ tags: pim
+
+# Create a random secret if needed
+- block:
+ - import_tasks: ../includes/get_rand_pass.yml
+ vars:
+ - pass_file: "{{ pim_root_dir }}/meta/ansible_secret"
+ - set_fact: pim_secret={{ rand_pass }}
+ when: pim_secret is not defined
+ tags: pim
diff --git a/roles/akeneo_pim/tasks/install.yml b/roles/akeneo_pim/tasks/install.yml
new file mode 100644
index 0000000..aefd1cb
--- /dev/null
+++ b/roles/akeneo_pim/tasks/install.yml
@@ -0,0 +1,72 @@
+---
+
+- name: Install needed tools
+ package:
+ name:
+ - make
+ tags: pim
+
+- when: pim_install_mode == 'upgrade'
+ block:
+ - name: Wipe install on upgrades
+ file: path={{ pim_root_dir }}/app state=absent
+
+ - name: Create app subdir
+ file: path={{ pim_root_dir }}/app state=directory owner={{ pim_user }} group={{ pim_user }}
+
+ tags: pim
+
+- when: pim_install_mode != 'none'
+ block:
+ - name: Deploy composer.json
+ template: src=composer.json.j2 dest={{ pim_root_dir }}/app/composer.json owner={{ pim_user }}
+ become_user: root
+
+ - name: Install Akeneo with Composer
+ composer:
+ working_dir: "{{ pim_root_dir }}/app"
+ executable: /bin/php{{ pim_php_version }}
+ command: install
+ become_user: "{{ pim_user }}"
+
+ - name: Install yarn globaly
+ npm:
+ name: yarn
+ path: "{{ pim_root_dir }}/app"
+ global: True
+
+ - name: Install typescript globaly
+ npm:
+ name: typescript
+ path: "{{ pim_root_dir }}/app"
+ global: True
+
+ tags: pim
+
+ # the PIM makefile has /usr/local/bin/composer hardcoded
+- name: Link composer in /usr/local/bin
+ file: src=/bin/composer dest=/usr/local/bin/composer state=link
+ tags: pim
+
+- import_tasks: ../includes/webapps_create_mysql_db.yml
+ vars:
+ - db_name: "{{ pim_db_name }}"
+ - db_user: "{{ pim_db_user }}"
+ - db_server: "{{ pim_db_server }}"
+ - db_pass: "{{ pim_db_pass }}"
+ tags: pim
+
+- name: Set correct SELinux context
+ sefcontext:
+ target: "{{ pim_root_dir }}(/.*)?"
+ setype: httpd_sys_content_t
+ state: present
+ when: ansible_selinux.status == 'enabled'
+ tags: pim
+
+- name: Install pre/post backup hooks
+ template: src={{ item }}-backup.j2 dest=/etc/backup/{{ item }}.d/pim_{{ pim_id }} mode=700
+ loop:
+ - pre
+ - post
+ tags: pim
diff --git a/roles/akeneo_pim/tasks/main.yml b/roles/akeneo_pim/tasks/main.yml
new file mode 100644
index 0000000..8ef41bb
--- /dev/null
+++ b/roles/akeneo_pim/tasks/main.yml
@@ -0,0 +1,10 @@
+---
+
+- include: user.yml
+- include: directories.yml
+- include: facts.yml
+- include: archive_pre.yml
+ when: pim_install_mode == 'upgrade'
+- include: install.yml
+- include: conf.yml
+- include: write_version.yml
diff --git a/roles/akeneo_pim/tasks/user.yml b/roles/akeneo_pim/tasks/user.yml
new file mode 100644
index 0000000..1dbe66f
--- /dev/null
+++ b/roles/akeneo_pim/tasks/user.yml
@@ -0,0 +1,9 @@
+---
+
+- name: Create user
+ user:
+ name: "{{ pim_user }}"
+ system: True
+ home: "{{ pim_root_dir }}"
+ shell: /sbin/nologin
+ tags: pim
diff --git a/roles/akeneo_pim/tasks/write_version.yml b/roles/akeneo_pim/tasks/write_version.yml
new file mode 100644
index 0000000..8f74ea6
--- /dev/null
+++ b/roles/akeneo_pim/tasks/write_version.yml
@@ -0,0 +1,5 @@
+---
+
+- name: Write current installed version
+ copy: content={{ pim_version }} dest={{ pim_root_dir }}/meta/ansible_version
+ tags: pim
diff --git a/roles/akeneo_pim/templates/composer.json.j2 b/roles/akeneo_pim/templates/composer.json.j2
new file mode 100644
index 0000000..0435746
--- /dev/null
+++ b/roles/akeneo_pim/templates/composer.json.j2
@@ -0,0 +1,44 @@
+{
+ "name": "akeneo/pim-community-standard",
+ "description": "The \"Akeneo Community Standard Edition\" distribution",
+ "license": "OSL-3.0",
+ "type": "project",
+ "authors": [
+ {
+ "name": "Akeneo",
+ "homepage": "http://www.akeneo.com"
+ }
+ ],
+ "autoload": {
+ "psr-0": {
+ "": "src/"
+ },
+ "psr-4": {
+ "Pim\\Upgrade\\": "upgrades/"
+ },
+ "exclude-from-classmap": [
+ "vendor/akeneo/pim-community-dev/src/Kernel.php"
+ ]
+ },
+ "require": {
+ "akeneo/pim-community-dev": "^{{ pim_version }}"
+ },
+ "require-dev": {
+ "doctrine/doctrine-migrations-bundle": "1.3.2",
+ "symfony/debug-bundle": "^4.4.7",
+ "symfony/web-profiler-bundle": "^4.4.7",
+ "symfony/web-server-bundle": "^4.4.7"
+ },
+ "scripts": {
+ "post-update-cmd": [
+ "bash vendor/akeneo/pim-community-dev/std-build/install-required-files.sh"
+ ],
+ "post-install-cmd": [
+ "bash vendor/akeneo/pim-community-dev/std-build/install-required-files.sh"
+ ],
+ "post-create-project-cmd": [
+ "bash vendor/akeneo/pim-community-dev/std-build/install-required-files.sh"
+ ]
+ },
+ "minimum-stability": "stable"
+}
diff --git a/roles/akeneo_pim/templates/env.j2 b/roles/akeneo_pim/templates/env.j2
new file mode 100644
index 0000000..c0142bd
--- /dev/null
+++ b/roles/akeneo_pim/templates/env.j2
@@ -0,0 +1,17 @@
+APP_ENV=prod
+APP_DEBUG=0
+APP_DATABASE_HOST={{ pim_db_server }}
+APP_DATABASE_PORT={{ pim_db_port }}
+APP_DATABASE_NAME={{ pim_db_name }}
+APP_DATABASE_USER={{ pim_db_user }}
+APP_DATABASE_PASSWORD={{ pim_db_pass | quote }}
+APP_DEFAULT_LOCALE=en
+APP_SECRET={{ pim_secret | quote }}
+APP_INDEX_HOSTS={{ pim_es_server }}
+APP_PRODUCT_AND_PRODUCT_MODEL_INDEX_NAME=akeneo_pim_product_and_product_model
+APP_CONNECTION_ERROR_INDEX_NAME=akeneo_connectivity_connection_error
+MAILER_URL=null://localhost&sender_address=no-reply@{{ ansible_domain }}
+AKENEO_PIM_URL={{ pim_public_url }}
+LOGGING_LEVEL=NOTICE
+APP_EVENTS_API_DEBUG_INDEX_NAME=akeneo_connectivity_connection_events_api_debug
+APP_PRODUCT_AND_PRODUCT_MODEL_INDEX_NAME=akeneo_pim_product_and_product_model
diff --git a/roles/akeneo_pim/templates/httpd.conf.j2 b/roles/akeneo_pim/templates/httpd.conf.j2
new file mode 100644
index 0000000..7cd0abb
--- /dev/null
+++ b/roles/akeneo_pim/templates/httpd.conf.j2
@@ -0,0 +1,43 @@
+{% if pim_web_alias is defined and pim_web_alias != False %}
+Alias /{{ pim_web_alias | regex_replace('^/','') }} {{ pim_root_dir }}/app/public
+{% else %}
+# No alias defined, create a vhost to access it
+{% endif %}
+
+
+ AllowOverride All
+ Options FollowSymLinks
+{% if pim_src_ip is defined and pim_src_ip | length > 0 %}
+ Require ip {{ pim_src_ip | join(' ') }}
+{% else %}
+ Require all granted
+{% endif %}
+
+ SetHandler "proxy:unix:/run/php-fpm/{{ pim_php_fpm_pool | default('pim_' + pim_id | string) }}.sock|fcgi://localhost"
+
+
+ RewriteEngine On
+
+ # Handle Authorization Header
+ RewriteCond %{HTTP:Authorization} .
+ RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
+
+ # Redirect Trailing Slashes If Not A Folder...
+ RewriteCond %{REQUEST_FILENAME} !-d
+ RewriteCond %{REQUEST_URI} (.+)/$
+ RewriteRule ^ %1 [L,R=301]
+
+ # Send Requests To Front Controller...
+ RewriteCond %{REQUEST_FILENAME} !-d
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteRule ^ index.php [L]
+
+
+ Require all denied
+
+
+
+
+
+ RewriteEngine Off
+
diff --git a/roles/akeneo_pim/templates/perms.sh.j2 b/roles/akeneo_pim/templates/perms.sh.j2
new file mode 100644
index 0000000..4cfedea
--- /dev/null
+++ b/roles/akeneo_pim/templates/perms.sh.j2
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+restorecon -R {{ pim_root_dir }}
+chown root:root {{ pim_root_dir }}
+chmod 700 {{ pim_root_dir }}
+setfacl -R -k -b {{ pim_root_dir }}
+setfacl -m u:{{ pim_user | default('apache') }}:rx,u:{{ httpd_user | default('apache') }}:x {{ pim_root_dir }}
+find {{ pim_root_dir }}/app -type f -exec chmod 644 "{}" \;
+find {{ pim_root_dir }}/app -type d -exec chmod 755 "{}" \;
+chown -R {{ pim_user }}:{{ pim_user }} {{ pim_root_dir }}/app
+
diff --git a/roles/akeneo_pim/templates/php.conf.j2 b/roles/akeneo_pim/templates/php.conf.j2
new file mode 100644
index 0000000..9ec5d98
--- /dev/null
+++ b/roles/akeneo_pim/templates/php.conf.j2
@@ -0,0 +1,35 @@
+[pim_{{ pim_id }}]
+
+listen.owner = root
+listen.group = apache
+listen.mode = 0660
+listen = /run/php-fpm/pim_{{ pim_id }}.sock
+user = {{ pim_user }}
+group = {{ pim_user }}
+catch_workers_output = yes
+
+pm = dynamic
+pm.max_children = 15
+pm.start_servers = 3
+pm.min_spare_servers = 3
+pm.max_spare_servers = 6
+pm.max_requests = 5000
+request_terminate_timeout = 5m
+
+php_flag[display_errors] = off
+php_admin_flag[log_errors] = on
+php_admin_value[error_log] = syslog
+php_admin_value[memory_limit] = 1024M
+php_admin_value[session.save_path] = {{ pim_root_dir }}/sessions
+php_admin_value[upload_tmp_dir] = {{ pim_root_dir }}/tmp
+php_admin_value[sys_temp_dir] = {{ pim_root_dir }}/tmp
+php_admin_value[post_max_size] = 200M
+php_admin_value[upload_max_filesize] = 200M
+php_admin_value[disable_functions] = system, show_source, symlink, exec, dl, shell_exec, passthru, phpinfo, escapeshellarg, escapeshellcmd
+php_admin_value[open_basedir] = {{ pim_root_dir }}:/usr/share/pear/:/usr/share/php/
+php_admin_value[max_execution_time] = 1200
+php_admin_value[max_input_time] = 1200
+php_admin_flag[allow_url_include] = off
+php_admin_flag[allow_url_fopen] = off
+php_admin_flag[file_uploads] = on
+php_admin_flag[session.cookie_httponly] = on
diff --git a/roles/akeneo_pim/templates/post-backup.j2 b/roles/akeneo_pim/templates/post-backup.j2
new file mode 100644
index 0000000..c21cfe3
--- /dev/null
+++ b/roles/akeneo_pim/templates/post-backup.j2
@@ -0,0 +1,3 @@
+#!/bin/bash -e
+
+rm -f {{ pim_root_dir }}/backup/*.sql.zst
diff --git a/roles/akeneo_pim/templates/pre-backup.j2 b/roles/akeneo_pim/templates/pre-backup.j2
new file mode 100644
index 0000000..c5c4195
--- /dev/null
+++ b/roles/akeneo_pim/templates/pre-backup.j2
@@ -0,0 +1,12 @@
+#!/bin/bash -e
+
+/usr/bin/mysqldump \
+{% if pim_db_server not in ['localhost','127.0.0.1'] %}
+ --user={{ pim_db_user | quote }} \
+ --password={{ pim_db_pass | quote }} \
+ --host={{ pim_db_server | quote }} \
+ --port={{ pim_db_port | quote }} \
+{% endif %}
+ --quick --single-transaction \
+ --add-drop-table {{ pim_db_name | quote }} | zstd -c > {{ pim_root_dir }}/backup/{{ pim_db_name }}.sql.zst
+