diff --git a/lib/ansible/modules/web_infrastructure/jboss.py b/lib/ansible/modules/web_infrastructure/jboss.py index 636cbe1f461..ddfd3e7e089 100644 --- a/lib/ansible/modules/web_infrastructure/jboss.py +++ b/lib/ansible/modules/web_infrastructure/jboss.py @@ -28,6 +28,8 @@ options: src: description: - The remote path of the application ear or war to deploy. + - Required when I(state=present). + - Ignored when I(state=absent). type: path deploy_path: default: /var/lib/jbossas/standalone/deployments @@ -42,25 +44,28 @@ options: type: str notes: - The JBoss standalone deployment-scanner has to be enabled in standalone.xml + - The module can wait until I(deployment) file is deployed/undeployed by deployment-scanner. + Duration of waiting time depends on scan-interval parameter from standalone.xml. - Ensure no identically named application is deployed through the JBoss CLI author: - Jeroen Hoekx (@jhoekx) """ EXAMPLES = r""" -- name: Deploy a hello world application +- name: Deploy a hello world application to the default deploy_path jboss: src: /tmp/hello-1.0-SNAPSHOT.war deployment: hello.war state: present -- name: Update the hello world application +- name: Update the hello world application to the non-default deploy_path jboss: src: /tmp/hello-1.1-SNAPSHOT.war + deploy_path: /opt/wildfly/deployment deployment: hello.war state: present -- name: Undeploy the hello world application +- name: Undeploy the hello world application from the default deploy_path jboss: deployment: hello.war state: absent @@ -74,6 +79,9 @@ import time from ansible.module_utils.basic import AnsibleModule +DEFAULT_DEPLOY_PATH = '/var/lib/jbossas/standalone/deployments' + + def is_deployed(deploy_path, deployment): return os.path.exists(os.path.join(deploy_path, "%s.deployed" % deployment)) @@ -91,10 +99,11 @@ def main(): argument_spec=dict( src=dict(type='path'), deployment=dict(type='str', required=True), - deploy_path=dict(type='path', default='/var/lib/jbossas/standalone/deployments'), + deploy_path=dict(type='path', default=DEFAULT_DEPLOY_PATH), state=dict(type='str', choices=['absent', 'present'], default='present'), ), - required_if=[('state', 'present', ('src',))] + required_if=[('state', 'present', ('src',))], + supports_check_mode=True ) result = dict(changed=False) @@ -107,11 +116,30 @@ def main(): if not os.path.exists(deploy_path): module.fail_json(msg="deploy_path does not exist.") + if state == 'absent' and src: + module.warn('Parameter src is ignored when state=absent') + elif state == 'present' and not os.path.exists(src): + module.fail_json(msg='Source file %s does not exist.' % src) + deployed = is_deployed(deploy_path, deployment) + # === when check_mode === + if module.check_mode: + if state == 'present': + if not deployed: + result['changed'] = True + + elif deployed: + if module.sha1(src) != module.sha1(os.path.join(deploy_path, deployment)): + result['changed'] = True + + elif state == 'absent' and deployed: + result['changed'] = True + + module.exit_json(**result) + # ======================= + if state == 'present' and not deployed: - if not os.path.exists(src): - module.fail_json(msg='Source file %s does not exist.' % src) if is_failed(deploy_path, deployment): # Clean up old failed deployment os.remove(os.path.join(deploy_path, "%s.failed" % deployment)) diff --git a/test/integration/targets/jboss/aliases b/test/integration/targets/jboss/aliases new file mode 100644 index 00000000000..e9fc78ee6de --- /dev/null +++ b/test/integration/targets/jboss/aliases @@ -0,0 +1,6 @@ +destructive +shippable/posix/group1 +skip/osx +skip/freebsd +skip/rhel +needs/root diff --git a/test/integration/targets/jboss/meta/main.yml b/test/integration/targets/jboss/meta/main.yml new file mode 100644 index 00000000000..000178657d9 --- /dev/null +++ b/test/integration/targets/jboss/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: +- setup_wildfly_server diff --git a/test/integration/targets/jboss/tasks/jboss.yml b/test/integration/targets/jboss/tasks/jboss.yml new file mode 100644 index 00000000000..9f9720a72f4 --- /dev/null +++ b/test/integration/targets/jboss/tasks/jboss.yml @@ -0,0 +1,236 @@ +# Copyright: (c) 2019, Andrew Klychkov (@Andersson007) +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +# Integration tests for jboss module. + +# helloworld.war (got from https://github.com/aeimer/java-example-helloworld-war/) license: +# MIT License +# +# Copyright (c) 2017 Alex Eimer +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# =============================== +# Module's note section contains: +# "- The JBoss standalone deployment-scanner has to be enabled in standalone.xml" +# +# Also from https://docs.jboss.org/author/display/WFLY10/Application+deployment?_sscc=t +# "Deployment content (for example, war, ear, jar, and sar files) can be placed +# in the standalone/deployments directory of the WildFly distribution, +# in order to be automatically deployed into the server runtime. +# For this to work the deployment-scanner subsystem must be present. +# The scanner periodically checks the contents of the deployments directory +# and reacts to changes by updating the server." +# Regarding the information above JBoss server must be installed and running for full test suite. +# We use WildFly server, free alternative, instead. See setup_wildfly_server role for more information. + +- vars: + war_file_1: 'helloworld-1.war' + war_file_1_path: '{{ wf_homedir }}/{{ war_file_1 }}' + fake_src_path: /fake/src + test_deployment: helloworld-1.war + task_parameters: &task_parameters + become_user: '{{ wf_user }}' + become: yes + register: result + + block: + - name: Create test files + <<: *task_parameters + get_url: + url: 'https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/jboss/{{ war_file_1 }}' + dest: '{{ wf_homedir }}' + + ################## + # Start the tests: + + # Test if state=present and not deployed, check_mode: + - name: jboss - deploy war in check_mode, the default deploy_path + <<: *task_parameters + jboss: + deployment: '{{ war_file_1 }}' + src: '{{ war_file_1_path }}' + check_mode: yes + + - assert: + that: + - result is changed + + # Check + - name: check that nothing changed after the previous step + <<: *task_parameters + file: + path: '{{ deploy_dir }}/{{ war_file_1 }}.deployed' + ignore_errors: yes + + - assert: + that: + - "'is absent' in result.msg" + + # Test if state=present and not deployed, actual mode: + - name: jboss - deploy war + <<: *task_parameters + jboss: + deployment: helloworld-1.war + deploy_path: '{{ deploy_dir }}' + src: '{{ war_file_1_path }}' + + - assert: + that: + - result is changed + + # Check + - name: check that the file is deployed after the previous step + <<: *task_parameters + file: + path: '{{ deploy_dir }}/{{ war_file_1 }}.deployed' + + - assert: + that: + - result.state == 'file' + + # Test if state=present and deployed in check mode, try again: + - name: jboss - try again to deploy war in check_mode, war is deployed now + <<: *task_parameters + jboss: + deployment: '{{ war_file_1 }}' + src: '{{ war_file_1_path }}' + deploy_path: '{{ deploy_dir }}' + check_mode: yes + + - assert: + that: + - result is not changed + + # Test if state=present and deployed, try again: + - name: jboss - try again to deploy war in actual mode, war is deployed now + <<: *task_parameters + jboss: + deployment: '{{ war_file_1 }}' + src: '{{ war_file_1_path }}' + deploy_path: '{{ deploy_dir }}' + + - assert: + that: + - result is not changed + + # Check + - name: check that nothing changed after the previous step + <<: *task_parameters + file: + path: '{{ deploy_dir }}/{{ war_file_1 }}.deployed' + + - assert: + that: + - result.state == 'file' + + # Test if state=absent and deployed: + - name: jboss - undeploy war in check_mode, war is deployed + <<: *task_parameters + jboss: + deployment: '{{ war_file_1 }}' + deploy_path: '{{ deploy_dir }}' + state: absent + check_mode: yes + + - assert: + that: + - result is changed + + - name: check that nothing actually changed after the previous step + <<: *task_parameters + file: + path: '{{ deploy_dir }}/{{ war_file_1 }}.deployed' + + - assert: + that: + - result.state == 'file' + + # Test if state=absent and deployed: + - name: jboss - undeploy war in actual mode, war is deployed + <<: *task_parameters + jboss: + deployment: '{{ war_file_1 }}' + deploy_path: '{{ deploy_dir }}' + state: absent + + - assert: + that: + - result is changed + + - name: check that file is undeployed after the previous step + <<: *task_parameters + file: + path: '{{ deploy_dir }}/{{ war_file_1 }}.undeployed' + + - assert: + that: + - result.state == 'file' + + # Test if state=absent and undeployed: + - name: jboss - undeploy war in check_mode, war is undeployed + <<: *task_parameters + jboss: + deployment: '{{ war_file_1 }}' + deploy_path: '{{ deploy_dir }}' + state: absent + check_mode: yes + + - assert: + that: + - result is not changed + + # Test if state=absent and undeployed: + - name: jboss - undeploy war in actual_mode, war is undeployed + <<: *task_parameters + jboss: + deployment: '{{ war_file_1 }}' + deploy_path: '{{ deploy_dir }}' + state: absent + + - assert: + that: + - result is not changed + + # Test fake src: + - name: jboss - test fake src + <<: *task_parameters + jboss: + deployment: '{{ war_file_1 }}' + deploy_path: '{{ deploy_dir }}' + src: '{{ fake_src_path }}' + state: present + ignore_errors: yes + + - assert: + that: + - result is failed + - "'Source file {{ fake_src_path }} does not exist.' in result.msg" + + # Test errors where state=present and src is not passed: + - name: jboss - must fail when state=present and src is not passed + <<: *task_parameters + jboss: + deployment: '{{ war_file_1 }}' + state: present + ignore_errors: yes + + - assert: + that: + - result is failed + - "'state is present but all of the following are missing: src' in result.msg" diff --git a/test/integration/targets/jboss/tasks/main.yml b/test/integration/targets/jboss/tasks/main.yml new file mode 100644 index 00000000000..23c77b10c0b --- /dev/null +++ b/test/integration/targets/jboss/tasks/main.yml @@ -0,0 +1 @@ +- import_tasks: jboss.yml diff --git a/test/integration/targets/setup_wildfly_server/defaults/main.yml b/test/integration/targets/setup_wildfly_server/defaults/main.yml new file mode 100644 index 00000000000..64019a04b3a --- /dev/null +++ b/test/integration/targets/setup_wildfly_server/defaults/main.yml @@ -0,0 +1,8 @@ +wf_tmp_dir: '{{ remote_tmp_dir }}/wildfly_tmp' +wf_homedir: '{{ wf_tmp_dir }}/wildfly' +wf_service_file_path: /etc/systemd/system/wildfly.service +wf_version: 16.0.0.Final +wf_user: wildfly +jboss_root: '{{ wf_homedir }}' +deploy_dir: '{{ jboss_root }}/standalone/deployments' +default_deploy_root: /var/lib/jbossas/standalone/deployments diff --git a/test/integration/targets/setup_wildfly_server/files/wildfly.conf b/test/integration/targets/setup_wildfly_server/files/wildfly.conf new file mode 100644 index 00000000000..4ff3293b720 --- /dev/null +++ b/test/integration/targets/setup_wildfly_server/files/wildfly.conf @@ -0,0 +1,8 @@ +# The configuration you want to run +WILDFLY_CONFIG=standalone.xml + +# The mode you want to run +WILDFLY_MODE=standalone + +# The address to bind to +WILDFLY_BIND=0.0.0.0 diff --git a/test/integration/targets/setup_wildfly_server/handlers/main.yml b/test/integration/targets/setup_wildfly_server/handlers/main.yml new file mode 100644 index 00000000000..98db569dbaa --- /dev/null +++ b/test/integration/targets/setup_wildfly_server/handlers/main.yml @@ -0,0 +1,13 @@ +- name: Stop wildfly (jboss) + systemd: + name: wildfly + state: stopped + ignore_errors: yes + +- name: Remove files + file: + path: '{{ item }}' + state: absent + loop: + - '{{ wf_service_file_path }}' + - '{{ default_deploy_root }}' diff --git a/test/integration/targets/setup_wildfly_server/meta/main.yml b/test/integration/targets/setup_wildfly_server/meta/main.yml new file mode 100644 index 00000000000..9f37e96cd90 --- /dev/null +++ b/test/integration/targets/setup_wildfly_server/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: +- setup_remote_tmp_dir diff --git a/test/integration/targets/setup_wildfly_server/tasks/main.yml b/test/integration/targets/setup_wildfly_server/tasks/main.yml new file mode 100644 index 00000000000..507c39b1f15 --- /dev/null +++ b/test/integration/targets/setup_wildfly_server/tasks/main.yml @@ -0,0 +1,94 @@ +- name: Skip unsupported platforms + meta: end_play + when: (ansible_distribution != 'CentOS') or + (ansible_distribution == 'CentOS' and ansible_distribution_major_version is not version('7', '>=')) + +- name: Install java + package: + name: java-1.8.0-openjdk-devel + +- name: Create wf_tmp_dir + file: + path: '{{ wf_tmp_dir }}' + state: directory + +- name: Download wildfly + get_url: + url: 'https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/setup_wildfly_server/wildfly-{{ wf_version }}.tar.gz' + dest: '{{ wf_tmp_dir }}/wildfly-{{ wf_version }}.tar.gz' + +- name: Unarchive tar + unarchive: + src: '{{ wf_tmp_dir }}/wildfly-{{ wf_version }}.tar.gz' + dest: '{{ wf_tmp_dir }}' + remote_src: yes + +- name: Remove tar + file: + path: '{{ wf_tmp_dir }}/wildfly-{{ wf_version }}.tar.gz' + state: absent + +- name: Create symlink + file: + src: '{{ wf_tmp_dir }}/wildfly-{{ wf_version }}' + dest: '{{ wf_tmp_dir }}/wildfly' + state: link + +- name: Create group for wildfly + group: + name: '{{ wf_user }}' + system: yes + +- name: Create user for wildfly + user: + name: '{{ wf_user }}' + system: yes + group: '{{ wf_user }}' + home: '{{ wf_homedir }}' + +- name: Set permissions + file: + path: '{{ remote_tmp_dir }}' + state: directory + owner: '{{ wf_user }}' + group: '{{ wf_user }}' + recurse: yes + +- name: Create config file + copy: + src: wildfly.conf + dest: '{{ wf_homedir }}/wildfly.conf' + +- name: Create launcher + template: + src: launch.sh.j2 + dest: '{{ wf_homedir }}/bin/launch.sh' + +- name: Make scripts executable + shell: 'chmod +x {{ wf_homedir }}/bin/*.sh' + +- name: Create service file + template: + src: wildfly.service.j2 + dest: '{{ wf_service_file_path }}' + +- name: Create directories for testing the default deploy_path + become: yes + file: + path: '{{ default_deploy_root }}' + state: directory + recurse: yes + owner: '{{ wf_user }}' + group: '{{ wf_user }}' + +- name: Create simlink for testing the default deploy_path + file: + state: link + src: '{{ deploy_dir }}' + dest: '{{ default_deploy_root }}/deployments' + +- name: Reload systemd and start wildfly + systemd: + daemon_reload: yes + name: wildfly + state: started diff --git a/test/integration/targets/setup_wildfly_server/templates/launch.sh.j2 b/test/integration/targets/setup_wildfly_server/templates/launch.sh.j2 new file mode 100644 index 00000000000..a01bcc513eb --- /dev/null +++ b/test/integration/targets/setup_wildfly_server/templates/launch.sh.j2 @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +if [ "x$WILDFLY_HOME" = "x" ]; then + WILDFLY_HOME="{{ wf_homedir }}" +fi + +if [[ "$1" == "domain" ]]; then + $WILDFLY_HOME/bin/domain.sh -c "$2" -b "$3" +else + $WILDFLY_HOME/bin/standalone.sh -c "$2" -b "$3" +fi diff --git a/test/integration/targets/setup_wildfly_server/templates/wildfly.service.j2 b/test/integration/targets/setup_wildfly_server/templates/wildfly.service.j2 new file mode 100644 index 00000000000..686c30193ee --- /dev/null +++ b/test/integration/targets/setup_wildfly_server/templates/wildfly.service.j2 @@ -0,0 +1,16 @@ +[Unit] +Description=The WildFly Application Server +After=syslog.target network.target +Before=httpd.service + +[Service] +Environment=LAUNCH_JBOSS_IN_BACKGROUND=1 +EnvironmentFile=-{{ wf_homedir }}/wildfly.conf +User=wildfly +LimitNOFILE=102642 +PIDFile=/var/run/wildfly/wildfly.pid +ExecStart={{ wf_homedir }}/bin/launch.sh $WILDFLY_MODE $WILDFLY_CONFIG $WILDFLY_BIND +StandardOutput=null + +[Install] +WantedBy=multi-user.target