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 +