diff --git a/aws_confluence_dc_node.yml b/aws_confluence_dc_node.yml new file mode 100644 index 0000000..74b239b --- /dev/null +++ b/aws_confluence_dc_node.yml @@ -0,0 +1,18 @@ +--- +- hosts: aws_node_local + become: true + + vars: + # See group_vars/aws_node_local.yml, which pull vars from the environment. + atl_product_family: "confluence" + atl_product_user: "confluence" + atl_product_edition: "confluence" + + roles: + - role: linux_common + - role: aws_common + - role: aws_efs_config + - role: product_common + - role: product_install + - role: database_init + - role: confluence_config diff --git a/group_vars/aws_node_local.yml b/group_vars/aws_node_local.yml index a69c57c..dfbfa74 100644 --- a/group_vars/aws_node_local.yml +++ b/group_vars/aws_node_local.yml @@ -17,7 +17,11 @@ atl_shared_mountpoint: "/media/atl" # FIXME: Some of these should be overridden from the environment? atl_home_base: "/var/atlassian/application-data" atl_product_home: "{{ atl_home_base }}/{{ atl_product_family }}" -atl_product_home_shared: "{{ atl_shared_mountpoint }}/{{ atl_product_family }}/shared" +atl_product_shared_home_map: + confluence: "shared-home" + jira: "shared" + stash: "shared" +atl_product_home_shared: "{{ atl_shared_mountpoint }}/{{ atl_product_family }}/{{ atl_product_shared_home_map[atl_product_family] }}" atl_product_shared_plugins: "{{ atl_product_home_shared }}/plugins/installed-plugins" atl_installation_base: "/opt/atlassian" @@ -33,6 +37,7 @@ atl_installer_temp: "{{ atl_installation_base }}/tmp" atl_product_version: "{{ lookup('env', 'ATL_PRODUCT_VERSION') | lower }}" atl_efs_id: "{{ lookup('env', 'ATL_EFS_ID') }}" +atl_aws_stack_name: "{{ lookup('env', 'ATL_AWS_STACK_NAME') }}" atl_db_host: "{{ lookup('env', 'ATL_DB_HOST') }}" atl_db_port: "{{ lookup('env', 'ATL_DB_PORT') or '5432' }}" diff --git a/roles/confluence_config/.yamllint b/roles/confluence_config/.yamllint new file mode 100644 index 0000000..a87f8ff --- /dev/null +++ b/roles/confluence_config/.yamllint @@ -0,0 +1,12 @@ +extends: default + +rules: + braces: + max-spaces-inside: 1 + level: error + brackets: + max-spaces-inside: 1 + level: error + line-length: disable + truthy: disable + trailing-spaces: false diff --git a/roles/confluence_config/defaults/main.yml b/roles/confluence_config/defaults/main.yml new file mode 100644 index 0000000..db918a0 --- /dev/null +++ b/roles/confluence_config/defaults/main.yml @@ -0,0 +1,47 @@ +--- + +atl_jvm_heap: "2048m" + +atl_db_timeout: "{{ lookup('env', 'ATL_DB_TIMEOUT') or '30' }}" +atl_db_idletestperiod: "{{ lookup('env', 'ATL_DB_IDLETESTPERIOD') or '100' }}" +atl_db_maxstatements: "{{ lookup('env', 'ATL_DB_MAXSTATEMENTS') or '0' }}" +atl_db_validate: "{{ lookup('env', 'ATL_ATL_DB_VALIDATE') or 'false' }}" +atl_db_acquireincrement: "{{ lookup('env', 'ATL_DB_ACQUIREINCREMENT') or '1' }}" + +atl_hazelcast_network_aws_tag_key: "Cluster" +atl_hazelcast_network_aws_host_header: "ec2.amazonaws.com" +atl_hazelcast_network_aws_iam_region: "{{ lookup('env', 'ATL_HAZELCAST_NETWORK_AWS_IAM_REGION') }}" +atl_hazelcast_network_aws_iam_role: "{{ lookup('env', 'ATL_HAZELCAST_NETWORK_AWS_IAM_ROLE') }}" +atl_hazelcast_network_aws_tag_value: "{{ lookup('env', 'ATL_HAZELCAST_NETWORK_AWS_TAG_VALUE') }}" + +atl_autologin_cookie_age: "{{ lookup('env', 'ATL_AUTOLOGIN_COOKIE_AGE') }}" +atl_synchrony_service_url: "{{ lookup('env', 'ATL_SYNCHRONY_SERVICE_URL') }}" + + +atl_catalina_opts: "" +atl_catalina_opts_extra: >- + -Datlassian.event.thread_pool_configuration.queue_size=4096 + -Datlassian.plugins.enable.wait=300 + -Dconfluence.upgrade.recovery.file.enabled=false + -Dfile.encoding=UTF-8 + -Djava.net.preferIPv4Stack=true + -Dshare.group.email.mapping=atlassian-all:atlassian-all@atlassian.com,atlassian-staff:atlassian-staff@atlassian.com + -XX:+PrintAdaptiveSizePolicy + -XX:+PrintGCDetails + -XX:+PrintTenuringDistribution + -Dsynchrony.proxy.enabled=false + -Dsynchrony.service.url={{ atl_synchrony_service_url }} + -Dconfluence.cluster.node.name={{ ansible_ec2_local_ipv4 | default(ansible_default_ipv4.address) }} + -Dconfluence.cluster.hazelcast.max.no.heartbeat.seconds=60 + +atl_tomcat_port: "8080" +atl_tomcat_mgmt_port: "8005" +atl_tomcat_acceptcount: "10" +atl_tomcat_connectiontimeout: "20000" +atl_tomcat_contextpath: "" +atl_tomcat_maxthreads: "200" +atl_tomcat_minsparethreads: "10" +atl_tomcat_protocol: "HTTP/1.1" +atl_tomcat_redirectport: "" +atl_tomcat_scheme: "http" +atl_tomcat_secure: "false" diff --git a/roles/confluence_config/molecule/default/Dockerfile.j2 b/roles/confluence_config/molecule/default/Dockerfile.j2 new file mode 100644 index 0000000..e6aa95d --- /dev/null +++ b/roles/confluence_config/molecule/default/Dockerfile.j2 @@ -0,0 +1,14 @@ +# Molecule managed + +{% if item.registry is defined %} +FROM {{ item.registry.url }}/{{ item.image }} +{% else %} +FROM {{ item.image }} +{% endif %} + +RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates && apt-get clean; \ + elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash && dnf clean all; \ + elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ + elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml && zypper clean -a; \ + elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \ + elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates && xbps-remove -O; fi diff --git a/roles/confluence_config/molecule/default/molecule.yml b/roles/confluence_config/molecule/default/molecule.yml new file mode 100644 index 0000000..33c377c --- /dev/null +++ b/roles/confluence_config/molecule/default/molecule.yml @@ -0,0 +1,32 @@ +--- +dependency: + name: galaxy +driver: + name: docker +lint: + name: yamllint +platforms: + - name: amazon_linux2 + image: amazonlinux:2 + groups: + - aws_node_local + - name: ubuntu_lts + image: ubuntu:bionic + groups: + - aws_node_local +provisioner: + name: ansible + options: + skip-tags: runtime_pkg + lint: + name: ansible-lint + options: + x: ["701"] + inventory: + links: + group_vars: ../../../../group_vars/ +verifier: + name: testinfra + lint: + name: flake8 + enabled: false diff --git a/roles/confluence_config/molecule/default/playbook.yml b/roles/confluence_config/molecule/default/playbook.yml new file mode 100644 index 0000000..1be669d --- /dev/null +++ b/roles/confluence_config/molecule/default/playbook.yml @@ -0,0 +1,20 @@ +--- +- name: Converge + hosts: all + vars: + atl_product_family: "confluence" + atl_product_edition: "confluence" + atl_product_user: "confluence" + atl_product_version: "latest" + atl_jdbc_user: 'confluence' + atl_jvm_heap: 'PLACEHOLDER' + atl_cluster_node_id: 'FAKEID' + atl_autologin_cookie_age: "COOKIEAGE" + ansible_ec2_local_ipv4: "1.1.1.1" + ansible_default_ipv4: "2.2.2.2" + + roles: + - role: linux_common + - role: product_common + - role: product_install + - role: confluence_config diff --git a/roles/confluence_config/molecule/default/tests/test_default.py b/roles/confluence_config/molecule/default/tests/test_default.py new file mode 100644 index 0000000..90e9293 --- /dev/null +++ b/roles/confluence_config/molecule/default/tests/test_default.py @@ -0,0 +1,61 @@ +import os +import pytest + +import testinfra.utils.ansible_runner + +testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( + os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all') + +def test_seraph_file(host): + f = host.file('/opt/atlassian/confluence/current/confluence/WEB-INF/classes/seraph-config.xml') + assert f.exists + assert f.contains('COOKIEAGE') + +def test_setenv_file(host): + f = host.file('/opt/atlassian/confluence/current/bin/setenv.sh') + assert f.exists + assert f.contains('-XmsPLACEHOLDER') + assert f.contains('-XmxPLACEHOLDER') + assert f.contains('-Dconfluence.cluster.node.name=1.1.1.1') + +def test_server_file(host): + f = host.file('/opt/atlassian/confluence/current/conf/server.xml') + assert f.exists + assert f.contains('Connector port="8080"') + assert f.contains('Server port="8005"') + assert f.contains('/media/atl/confluence/shared-home') + assert f.contains('org.postgresql.Driver') diff --git a/roles/confluence_config/tasks/main.yml b/roles/confluence_config/tasks/main.yml new file mode 100644 index 0000000..2be0221 --- /dev/null +++ b/roles/confluence_config/tasks/main.yml @@ -0,0 +1,76 @@ +--- + +- name: Create application directories + file: + path: "{{ item }}" + state: directory + mode: 0750 + owner: "{{ atl_product_user }}" + group: "{{ atl_product_user }}" + with_items: + - "{{ atl_product_home }}" + - "{{ atl_product_home_shared }}" + - "{{ atl_product_shared_plugins }}" + changed_when: false # For Molecule idempotence check + + +- name: Create Tomcat server config + template: + src: server.xml.j2 + dest: "{{ atl_product_installation_versioned }}/conf/server.xml" + +- name: Override JVM memory settings. + replace: + path: "{{ atl_product_installation_versioned }}/bin/setenv.sh" + regexp: "-{{ item }}\\d+m " + replace: "-{{ item }}{{ atl_jvm_heap }} " + with_items: + - 'Xmx' + - 'Xms' + +- name: Set the Tomcat environment + lineinfile: + path: "{{ atl_product_installation_versioned }}/bin/setenv.sh" + insertafter: "EOF" + line: 'export CATALINA_OPTS="${CATALINA_OPTS} {{ atl_catalina_opts }} {{ atl_catalina_opts_extra }}"' + + +- name: Configure login properties + template: + src: seraph-config.xml.j2 + dest: "{{ atl_product_installation_versioned }}/confluence/WEB-INF/classes/seraph-config.xml" + +- name: Create Confluence configuration + template: + src: confluence.cfg.xml.j2 + dest: "{{ atl_product_home }}/confluence.cfg.xml" + owner: "{{ atl_product_user }}" + group: "{{ atl_product_user }}" + + +- name: Limit permissions on the installation directory + file: + path: "{{ atl_product_installation_versioned }}" + owner: "root" + group: "root" + mode: "u=rwX,g=rX,o=rX" + recurse: true + with_items: + - "{{ atl_installer_temp }}" + - "{{ atl_product_installation_versioned }}" + - "{{ atl_product_version_cache_dir }}" + changed_when: false # For Molecule idempotence check + +- name: Grant access to the product working directories + file: + path: "{{ item }}" + state: directory + mode: "u=rwX,g=rX,o-rwx" + owner: "{{ atl_product_user }}" + group: "{{ atl_product_user }}" + recurse: true + with_items: + - "{{ atl_product_installation_versioned }}/logs" + - "{{ atl_product_installation_versioned }}/temp" + - "{{ atl_product_installation_versioned }}/work" + changed_when: false # For Molecule idempotence check diff --git a/roles/confluence_config/templates/confluence.cfg.xml.j2 b/roles/confluence_config/templates/confluence.cfg.xml.j2 new file mode 100644 index 0000000..4b5368c --- /dev/null +++ b/roles/confluence_config/templates/confluence.cfg.xml.j2 @@ -0,0 +1,42 @@ + + + + + setupstart + custom + 0 + + + postgresql + database-type-standard + com.atlassian.confluence.impl.hibernate.dialect.PostgreSQLDialect + ${localHome}/temp + ${confluenceHome}/attachments + + {{ atl_db_driver }} + {{ atl_jdbc_url }} + {{ atl_jdbc_user }} + {{ atl_jdbc_password }} + {{ atl_db_poolminsize }} + {{ atl_db_poolmaxsize }} + {{ atl_db_timeout }} + {{ atl_db_idletestperiod }} + {{ atl_db_maxstatements }} + {{ atl_db_validate }} + {{ atl_db_acquireincrement }} + select version(); + + {{ atl_product_home_shared }} + true + {{ atl_product_home_shared }} + {{ atl_hazelcast_network_aws_iam_role }} + {{ atl_hazelcast_network_aws_iam_region }} + {{ atl_hazelcast_network_aws_host_header }} + {{ atl_hazelcast_network_aws_tag_key }} + {{ atl_hazelcast_network_aws_tag_value }} + aws + {{ atl_aws_stack_name }} + 1 + + + diff --git a/roles/confluence_config/templates/seraph-config.xml.j2 b/roles/confluence_config/templates/seraph-config.xml.j2 new file mode 100644 index 0000000..8c91e87 --- /dev/null +++ b/roles/confluence_config/templates/seraph-config.xml.j2 @@ -0,0 +1,71 @@ + + + + login.url + /login.action?os_destination=${originalurl}&permissionViolation=true + + + link.login.url + /login.action + + + cookie.encoding + cNf + + + login.cookie.key + seraph.confluence + + + {% if atl_autologin_cookie_age is defined and atl_autologin_cookie_age|length %} + + autologin.cookie.age + {{ atl_autologin_cookie_age }} + + {% endif %} + + + + authentication.type + os_authType + + + + + invalidate.session.on.login + true + + + + invalidate.session.exclude.list + + + + + + + + + + + + + + + + + + + + + + config.file + seraph-paths.xml + + + + + + + diff --git a/roles/confluence_config/templates/server.xml.j2 b/roles/confluence_config/templates/server.xml.j2 new file mode 100644 index 0000000..9e55982 --- /dev/null +++ b/roles/confluence_config/templates/server.xml.j2 @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + {% if atl_tomcat_redirectport is defined and atl_tomcat_redirectport != '' %} + + {% endif %} + + + + + + + + + + + + + + + + +