Migrating to JWS 6 using Ansible
Tags: automation, ansible, tomcat, java
Published: 2023-12-20 23:00:00

In this article, we'll discuss how to use the redhat.jws Ansible collection to automate the upgrade of a JBoss Web Server instance from 5.7 to the version 6.0. First, we'll use Ansible to install JWS 5.7 on the target system and then we'll use another playbook to perform the migration, thus ensuring that the target JWS instance has been upgraded successfully.

# Prerequisites

To support this demonstration you will first need to have a working Ansible environment. This involves having Ansible installed on the local (control) machine and one or several target hosts. As we are using the certified Ansible collection provided by Red Hat, Ansible needs to be configured to use Red Hat Ansible Automation Hub to retrieve content. Please refer to the official documentation on how to configure your machine.

Once complete, install the redhat.jws collection on the control node using `ansible-galaxy`:

```
    $ ansible-galaxy collection install redhat.jws
    Starting galaxy collection install process
    Process install dependency map
    Starting collection install process
    Downloading https://console.redhat.com/api/automation-hub/v3/plugin/ansible/content/published/collections/artifacts/redhat-jws-1.2.4.tar.gz to /root/.ansible/tmp/ansible-local-377j77fwws/tmpog8w22ut/redhat-jws-1.2.4-pi6vhlev
    Installing 'redhat.jws:1.2.4' to '/root/.ansible/collections/ansible_collections/redhat/jws'
    Downloading https://console.redhat.com/api/automation-hub/v3/plugin/ansible/content/published/collections/artifacts/redhat-runtimes_common-1.1.3.tar.gz to /root/.ansible/tmp/ansible-local-377j77fwws/tmpog8w22ut/redhat-runtimes_common-1.1.3-pg3nqnfm redhat.jws:1.2.4 was installed successfully
    Downloading https://console.redhat.com/api/automation-hub/v3/plugin/ansible/content/published/collections/artifacts/ansible-posix-1.5.4.tar.gz to /root/.ansible/tmp/ansible-local-377j77fwws/tmpog8w22ut/ansible-posix-1.5.4-kt8e4_oe Installing 'redhat.runtimes_common:1.1.3' to '/root/.ansible/collections/ansible_collections/redhat/runtimes_common' redhat.runtimes_common:1.1.3 was installed successfully
    Installing 'ansible.posix:1.5.4' to '/root/.ansible/collections/ansible_collections/ansible/posix' ansible.posix:1.5.4 was installed successfully
```
Note that the installation of the collection also ensures that the required dependencies are available.

Once all of the prerequisites have been completed, you can either download the zip files of JWS versions 5.7 and 6.0 from the Red Hat customer portal manually  or provide details related to your Red Hat  service account to Ansible. More information on how to create a service account can be found here:

```
    $ cat service_account.yml
    ---
    rhn_username: <service_account_id> 
    rhn_password: <password>
```
For simplicity’s sake, in this demonstration, we'll work with already downloaded zip files, placed in the main directory of the Ansible project. Note that it means the zip files are located on the controller, not the target systems.

# Installation of JWS 5.7

In real life, there is a good chance that users will already have an existing deployment of JWS (or maybe Apache Tomcat) they want to migrate from. For the demonstration in this article to be easily reproducible, however, we'll install a JWS server from the beginning to simulate this situation.

Using the redhat.jws collection, you can easily install and set up a JWS server using the following playbook:

```
    ---
    - name: "Red Hat JBoss Web Server installation and configuration"
      hosts: all
      become: True
      vars_files:
        - jws5_vars.yml 
      collections:
        - redhat.jws roles:
        - redhat.jws.jws
```

The playbook is mostly self-explanatory, however, we'll provide additional commentary on the meaning of a few variables located in the `jws5_vars.yml` file:

```
    # version java used to run JWS jws_java_version: 11
    # name of the systemd service associated JWS jws_service_name: jws5
    # Path to directory containing the zip files retrieved from Red Hat Customer Portal jws_archive_repository: "{{ lookup('env', 'PWD') }}"
    # Version of JWS used jws_version: 5.7.0
    # Name of the zipfile on the controller zipfile_name: jws-5.7.0-application-server.zip
```

Let's run the playbook to install our "legacy" JWS server:

```
$ ansible-playbook -i inventory jws5.yml

PLAY [Red Hat JBoss Web Server installation and configuration] *****************

TASK [Gathering Facts] *********************************************************
ok: [localhost]

TASK [redhat.jws.jws : Validating arguments against arg spec 'main'] ***********
ok: [localhost]

TASK [redhat.jws.jws : Set default values] *************************************
skipping: [localhost]

TASK [redhat.jws.jws : Set default values (jws)] *******************************
ok: [localhost]

TASK [redhat.jws.jws : Set jws_home to /opt/jws-5.7/tomcat if not already defined] ***
ok: [localhost]

TASK [redhat.jws.jws : Check that jws_home has been defined.] ******************
ok: [localhost] => {
	"changed": false,
	"msg": "All assertions passed"
}

TASK [redhat.jws.jws : Add firewalld to dependencies list (if enabled).] *******
skipping: [localhost]

TASK [redhat.jws.jws : Install required dependencies] **************************
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost => (item=zip)
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost => (item=unzip)
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost => (item=tzdata)

TASK [redhat.jws.jws : Check arguments] ****************************************
ok: [localhost]

TASK [redhat.jws.jws : Test if package zip is already installed] ***************
ok: [localhost]

TASK [redhat.jws.jws : Check arguments] ****************************************
ok: [localhost]

TASK [redhat.jws.jws : Test if package unzip is already installed] *************
ok: [localhost]

TASK [redhat.jws.jws : Check arguments] ****************************************
ok: [localhost]

TASK [redhat.jws.jws : Test if package tzdata is already installed] ************
ok: [localhost]

TASK [redhat.jws.jws : Install required dependencies for natives] **************
skipping: [localhost] => (item=openssl)
skipping: [localhost] => (item=apr)
skipping: [localhost]

TASK [redhat.jws.jws : Ensure tomcatjss rpm is not installed] ******************
ok: [localhost]

TASK [redhat.jws.jws : Include tasks for java jvm installation] ****************
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/java_install.yml for localhost

TASK [redhat.jws.jws : Set rpm name with version] ******************************
ok: [localhost]

TASK [redhat.jws.jws : Install java-11-openjdk-headless] ***********************
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost

TASK [redhat.jws.jws : Check arguments] ****************************************
ok: [localhost]

TASK [redhat.jws.jws : Test if package java-11-openjdk-headless is already installed] ***
ok: [localhost]

TASK [redhat.jws.jws : Determine JAVA_HOME for selected JVM RPM] ***************
ok: [localhost]

TASK [redhat.jws.jws : Create group: tomcat] ***********************************
ok: [localhost]

TASK [redhat.jws.jws : Create user: tomcat] ************************************
changed: [localhost]

TASK [redhat.jws.jws : Check state of install_dir: /opt] ***********************
ok: [localhost]

TASK [redhat.jws.jws : Ensure install dir is created: /opt] ********************
skipping: [localhost]

TASK [redhat.jws.jws : Include install tasks] **********************************
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/install.yml for localhost

TASK [redhat.jws.jws : Check arguments] ****************************************
ok: [localhost]

TASK [redhat.jws.jws : Check working directory /work for local repository] *****
ok: [localhost]

TASK [redhat.jws.jws : Display install method] *********************************
ok: [localhost] => {
	"msg": "Install method: zipfiles"
}

TASK [redhat.jws.jws : Set defaults values based on facts (if values not provided)] ***
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/install/defaults.yml for localhost

TASK [redhat.jws.jws : Set filename for JWS zipfile] ***************************
skipping: [localhost]

TASK [redhat.jws.jws : Set native zipfile architecture (if not provided)] ******
ok: [localhost]

TASK [redhat.jws.jws : Set RHEL major version based on facts (if not provided).] ***
ok: [localhost]

TASK [redhat.jws.jws : Set filename for JWS native zipfile] ********************
ok: [localhost]

TASK [redhat.jws.jws : Include installation tasks using zipfiles method] *******
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/install/local.yml for localhost

TASK [redhat.jws.jws : Deploy jws-5.7.0-application-server.zip to target.] *****
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/install/deploy_archive.yml for localhost

TASK [redhat.jws.jws : Check that required parameters have been provided.] *****
ok: [localhost]

TASK [redhat.jws.jws : Check download archive path on target: /opt/jws-5.7.0-application-server.zip] ***
ok: [localhost]

TASK [redhat.jws.jws : Retrieve zipfiles, if missing, from RHN (if credentials provided)] ***
skipping: [localhost]

TASK [redhat.jws.jws : Retrieve zipfiles from URL (if provided).] **************
skipping: [localhost]

TASK [redhat.jws.jws : Copy archives /work/jws-5.7.0-application-server.zip to target nodes: /opt/jws-5.7.0-application-server.zip] ***
changed: [localhost]

TASK [redhat.jws.jws : Deploy jws-5.7.0-application-server-RHEL8-x86_64.zip to target.] ***
skipping: [localhost]

TASK [redhat.jws.jws : Include installation tasks for zip operations] **********
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/install/zipfiles.yml for localhost

TASK [redhat.jws.jws : Check arguments] ****************************************
ok: [localhost]

TASK [redhat.jws.jws : Add zipfile to unarchive list] **************************
ok: [localhost]

TASK [redhat.jws.jws : Add native zipfile to unarchive list] *******************
skipping: [localhost]

TASK [redhat.jws.jws : Install Jboss Web Server and required binaries from local zipfiles (install method: zipfiles) to /opt] ***
changed: [localhost] => (item={'src': 'jws-5.7.0-application-server.zip', 'creates': '/opt/jws-5.7/tomcat/bin'})

TASK [redhat.jws.jws : Move the zipfile extracted directory to custom jws_home] ***
skipping: [localhost]

TASK [redhat.jws.jws : Move the version.txt to custom jws_home] ****************
skipping: [localhost]

TASK [redhat.jws.jws : Include installation tasks for rpm method] **************
skipping: [localhost]

TASK [redhat.jws.jws : Include systemd tasks] **********************************
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/systemd/systemd.yml for localhost

TASK [redhat.jws.jws : Check arguments] ****************************************
ok: [localhost]

TASK [redhat.jws.jws : Ensure requirements for systemd] ************************
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost => (item=systemd)
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost => (item=procps-ng)

TASK [redhat.jws.jws : Check arguments] ****************************************
ok: [localhost]

TASK [redhat.jws.jws : Test if package systemd is already installed] ***********
ok: [localhost]

TASK [redhat.jws.jws : Check arguments] ****************************************
ok: [localhost]

TASK [redhat.jws.jws : Test if package procps-ng is already installed] *********
ok: [localhost]

TASK [redhat.jws.jws : Set required default for jws_service_conf if not provided.] ***
ok: [localhost]

TASK [redhat.jws.jws : Set required default for jws_service_conf if not provided.] ***
ok: [localhost]

TASK [redhat.jws.jws : Set required default for jws_service_conf if not provided.] ***
ok: [localhost]

TASK [redhat.jws.jws : Ensure service script is deployed] **********************
changed: [localhost]

TASK [redhat.jws.jws : Ensure service configurations files is deployed: /opt/jws-5.7/tomcat/conf/jws5.conf] ***
changed: [localhost]

TASK [redhat.jws.jws : Ensure systemd service is configured] *******************
changed: [localhost]

TASK [redhat.jws.jws : Include patch install tasks] ****************************
skipping: [localhost]

TASK [redhat.jws.jws : Ensure /opt/jws-5.7/tomcat/ directories have appropriate privileges] ***
ok: [localhost] => (item=conf)
ok: [localhost] => (item=temp)
ok: [localhost] => (item=logs)
ok: [localhost] => (item=webapps)
ok: [localhost] => (item=bin)

TASK [redhat.jws.jws : Ensure /opt/jws-5.7/tomcat/ files have the recommended priviliges, owner and group] ***
changed: [localhost] => (item=./conf/catalina.properties)
changed: [localhost] => (item=./conf/catalina.policy)
changed: [localhost] => (item=./conf/logging.properties)
changed: [localhost] => (item=./conf/jaspic-providers.xml)
changed: [localhost] => (item=conf/tomcat-users.xml)

TASK [redhat.jws.jws : Include ajp sanity check tasks] *************************
skipping: [localhost]

TASK [redhat.jws.jws : Include https sanity check tasks] ***********************
skipping: [localhost]

TASK [redhat.jws.jws : Deploy custom configuration files] **********************
changed: [localhost] => (item={'template': 'templates/server.xml.j2', 'dest': '/opt/jws-5.7/tomcat/./conf/server.xml'})
changed: [localhost] => (item={'template': 'templates/web.xml.j2', 'dest': '/opt/jws-5.7/tomcat/./conf/web.xml'})
changed: [localhost] => (item={'template': 'templates/context.xml.j2', 'dest': '/opt/jws-5.7/tomcat/./conf/context.xml'})
changed: [localhost] => (item={'template': 'templates/catalina.properties.j2', 'dest': '/opt/jws-5.7/tomcat/./conf/catalina.properties'})

TASK [redhat.jws.jws : Include selinux configuration tasks] ********************
skipping: [localhost]

TASK [redhat.jws.jws : Remove apps] ********************************************
ok: [localhost] => (item=examples)

TASK [redhat.jws.jws : Create vault configuration (if enabled)] ****************
skipping: [localhost]

TASK [redhat.jws.jws : Ensure firewalld, if enabled, allows communication over 8080.] ***
skipping: [localhost]

RUNNING HANDLER [redhat.jws.jws : Reload Systemd] ******************************
ok: [localhost]

RUNNING HANDLER [redhat.jws.jws : Ensure Jboss Web Server runs under systemd] ***
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/systemd/service.yml for localhost

RUNNING HANDLER [redhat.jws.jws : Check arguments] *****************************
ok: [localhost]

RUNNING HANDLER [redhat.jws.jws : Enable jws.service] **************************
changed: [localhost]

RUNNING HANDLER [redhat.jws.jws : Start jws.service] ***************************
changed: [localhost]

RUNNING HANDLER [redhat.jws.jws : Restart Jboss Web Server service] ************
changed: [localhost]

PLAY RECAP *********************************************************************
```
Let's verify that the server is, indeed, successfully installed and available:

```
$ systemctl status jws5 ● jws5.service - Jboss Web Server
    Loaded: loaded (/usr/lib/systemd/system/jws5.service; enabled; vendor preset: disabled)
    Active: active (running) since Wed 2023-11-29 16:23:54 UTC; 8s ago
    Process: 2137 ExecStop=/opt/jws-5.7/tomcat/bin/systemd-service.sh stop (code=exited, status=0/SUCCESS)
    Main PID: 2187 (java)
    CGroup: /system.slice/jws5.service └─2187 /etc/alternatives/jre_11/bin/java -Djava.util.logging.config.file=/opt/jws-5.7/tomcat/conf/logging.properties -Djava.>
    Nov 29 16:23:54 62bfd7b30ce4 systemd[1]: Started Jboss Web Server.
    Nov 29 16:23:54 62bfd7b30ce4 systemd-service.sh[2178]: Tomcat started.
    Nov 29 16:23:54 62bfd7b30ce4 systemd-service.sh[2177]: Tomcat runs with PID: 2187
```
# Performing the migration to JWS 6

Now that we have a "legacy" system in place, we can focus on the migration. In order to migrate a system from JWS 5 to JWS 6, we'll first need to shut down the existing service (JWS 5) before performing the install of JWS 6. For this last part, we'll simply reuse the same role from the `redhat.jws` collection we used previously. We'll also use the same vars file to reuse the same configuration of the server, overriding only the few variables that differ for this new version of the server.

The following playbook could be written to accomplish migrating JWS from version 5 to 6:

```
    ---
    - name: "Migrate JWS5 to JWS6"
      hosts: all
      gather_facts: no
      serial:
    	- 1
    	- 30%
    	- 60%
      vars_files:
    	- vars.yml
      pre_tasks:
    	- name: "Ensure JWS5 is no longer running"
      	ansible.builtin.service:
        	name: "{{ jws_service_name }}"
        	state: stopped
      tasks:
        - name: "Migrate to JWS 6"
          ansible.builtin.include_role:
            name: redhat.jws.jws
          vars:
             # overriding only the vars required
              jws_version: 6.0.0
              jws_service_name: jws6
              zipfile_name: jws-6.0.0-application-server.zip
```

Now, let's run this new playbook:

`$ ansible-playbook -i inventory jws5-to-6.yml`

```
    PLAY [Migrate JWS5 to JWS6] ****************************************************

    TASK [Ensure JWS5 is no longer running] ****************************************
    ok: [localhost]

    TASK [Install JWS 6] ***********************************************************

    TASK [redhat.jws.jws : Validating arguments against arg spec 'main'] ***********
    ok: [localhost]

    TASK [redhat.jws.jws : Set default values] *************************************
    skipping: [localhost]

    TASK [redhat.jws.jws : Set default values (jws)] *******************************
    ok: [localhost]

    TASK [redhat.jws.jws : Set jws_home to /opt/jws-6.0/tomcat if not already defined] ***
    ok: [localhost]

    TASK [redhat.jws.jws : Check that jws_home has been defined.] ******************
    ok: [localhost] => {
    	"changed": false,
    	"msg": "All assertions passed"
    }

    TASK [redhat.jws.jws : Add firewalld to dependencies list (if enabled).] *******
    skipping: [localhost]

    TASK [redhat.jws.jws : Install required dependencies] **************************
    included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost => (item=zip)
    included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost => (item=unzip)
    included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost => (item=tzdata)

    TASK [redhat.jws.jws : Check arguments] ****************************************
    ok: [localhost]

    TASK [redhat.jws.jws : Test if package zip is already installed] ***************
    ok: [localhost]

    TASK [redhat.jws.jws : Check arguments] ****************************************
    ok: [localhost]

    TASK [redhat.jws.jws : Test if package unzip is already installed] *************
    ok: [localhost]

    TASK [redhat.jws.jws : Check arguments] ****************************************
    ok: [localhost]

    TASK [redhat.jws.jws : Test if package tzdata is already installed] ************
    ok: [localhost]

    TASK [redhat.jws.jws : Install required dependencies for natives] **************
    skipping: [localhost] => (item=openssl)
    skipping: [localhost] => (item=apr)
    skipping: [localhost]

    TASK [redhat.jws.jws : Ensure tomcatjss rpm is not installed] ******************
    ok: [localhost]

    TASK [redhat.jws.jws : Include tasks for java jvm installation] ****************
    included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/java_install.yml for localhost

    TASK [redhat.jws.jws : Set rpm name with version] ******************************
    ok: [localhost]

    TASK [redhat.jws.jws : Install java-11-openjdk-headless] ***********************
    included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost

    TASK [redhat.jws.jws : Check arguments] ****************************************
    ok: [localhost]

    TASK [redhat.jws.jws : Test if package java-11-openjdk-headless is already installed] ***
    ok: [localhost]

    TASK [redhat.jws.jws : Determine JAVA_HOME for selected JVM RPM] ***************
    ok: [localhost]

    TASK [redhat.jws.jws : Create group: tomcat] ***********************************
    ok: [localhost]

    TASK [redhat.jws.jws : Create user: tomcat] ************************************
    changed: [localhost]

    TASK [redhat.jws.jws : Check state of install_dir: /opt] ***********************
    ok: [localhost]

    TASK [redhat.jws.jws : Ensure install dir is created: /opt] ********************
    skipping: [localhost]

    TASK [redhat.jws.jws : Include install tasks] **********************************
    included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/install.yml for localhost

    TASK [redhat.jws.jws : Check arguments] ****************************************
    ok: [localhost]

    TASK [redhat.jws.jws : Check working directory /work for local repository] *****
    ok: [localhost]

    TASK [redhat.jws.jws : Display install method] *********************************
    ok: [localhost] => {
    	"msg": "Install method: zipfiles"
    }

    TASK [redhat.jws.jws : Set defaults values based on facts (if values not provided)] ***
    included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/install/defaults.yml for localhost

    TASK [redhat.jws.jws : Set filename for JWS zipfile] ***************************
    skipping: [localhost]

    TASK [redhat.jws.jws : Set native zipfile architecture (if not provided)] ******
    ok: [localhost]

    TASK [redhat.jws.jws : Set RHEL major version based on facts (if not provided).] ***
    ok: [localhost]

    TASK [redhat.jws.jws : Set filename for JWS native zipfile] ********************
    ok: [localhost]

    TASK [redhat.jws.jws : Include installation tasks using zipfiles method] *******
    included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/install/local.yml for localhost

    TASK [redhat.jws.jws : Deploy jws-6.0.0-application-server.zip to target.] *****
    included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/install/deploy_archive.yml for localhost

    TASK [redhat.jws.jws : Check that required parameters have been provided.] *****
    ok: [localhost]

    TASK [redhat.jws.jws : Check download archive path on target: /opt/jws-6.0.0-application-server.zip] ***
    ok: [localhost]

    TASK [redhat.jws.jws : Retrieve zipfiles, if missing, from RHN (if credentials provided)] ***
    skipping: [localhost]

    TASK [redhat.jws.jws : Retrieve zipfiles from URL (if provided).] **************
    skipping: [localhost]

    TASK [redhat.jws.jws : Copy archives /work/jws-6.0.0-application-server.zip to target nodes: /opt/jws-6.0.0-application-server.zip] ***
    changed: [localhost]

    TASK [redhat.jws.jws : Deploy jws-6.0.0-application-server-RHEL8-x86_64.zip to target.] ***
    skipping: [localhost]

    TASK [redhat.jws.jws : Include installation tasks for zip operations] **********
    included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/install/zipfiles.yml for localhost

    TASK [redhat.jws.jws : Check arguments] ****************************************
    ok: [localhost]

    TASK [redhat.jws.jws : Add zipfile to unarchive list] **************************
    ok: [localhost]

    TASK [redhat.jws.jws : Add native zipfile to unarchive list] *******************
    skipping: [localhost]

    TASK [redhat.jws.jws : Install Jboss Web Server and required binaries from local zipfiles (install method: zipfiles)] ***
    changed: [localhost] => (item={'src': 'jws-6.0.0-application-server.zip', 'creates': '/opt/jws-6.0/tomcat/bin'})

    TASK [redhat.jws.jws : Move the zipfile extracted directory to custom jws_home] ***
    skipping: [localhost]

    TASK [redhat.jws.jws : Move the version.txt to custom jws_home] ****************
    skipping: [localhost]

    TASK [redhat.jws.jws : Include installation tasks for rpm method] **************
    skipping: [localhost]

    TASK [redhat.jws.jws : Include systemd tasks] **********************************
    included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/systemd/systemd.yml for localhost

    TASK [redhat.jws.jws : Check arguments] ****************************************
    ok: [localhost]

    TASK [redhat.jws.jws : Ensure requirements for systemd] ************************
    included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost => (item=systemd)
    included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost => (item=procps-ng)

    TASK [redhat.jws.jws : Check arguments] ****************************************
    ok: [localhost]

    TASK [redhat.jws.jws : Test if package systemd is already installed] ***********
    ok: [localhost]

    TASK [redhat.jws.jws : Check arguments] ****************************************
    ok: [localhost]

    TASK [redhat.jws.jws : Test if package procps-ng is already installed] *********
    ok: [localhost]

    TASK [redhat.jws.jws : Set required default for jws_service_conf if not provided.] ***
    ok: [localhost]

    TASK [redhat.jws.jws : Set required default for jws_service_conf if not provided.] ***
    ok: [localhost]

    TASK [redhat.jws.jws : Set required default for jws_service_conf if not provided.] ***
    ok: [localhost]

    TASK [redhat.jws.jws : Ensure service script is deployed] **********************
    changed: [localhost]

    TASK [redhat.jws.jws : Ensure service configurations files is deployed: /opt/jws-6.0/tomcat/conf/jws6.conf] ***
    changed: [localhost]

    TASK [redhat.jws.jws : Ensure systemd service is configured] *******************
    changed: [localhost]

    TASK [redhat.jws.jws : Include patch install tasks] ****************************
    skipping: [localhost]

    TASK [redhat.jws.jws : Ensure /opt/jws-6.0/tomcat/ directories have appropriate privileges] ***
    ok: [localhost] => (item=conf)
    ok: [localhost] => (item=temp)
    ok: [localhost] => (item=logs)
    ok: [localhost] => (item=webapps)
    ok: [localhost] => (item=bin)

    TASK [redhat.jws.jws : Ensure /opt/jws-6.0/tomcat/ files have the recommended priviliges, owner and group] ***
    changed: [localhost] => (item=./conf/catalina.properties)
    changed: [localhost] => (item=./conf/catalina.policy)
    changed: [localhost] => (item=./conf/logging.properties)
    changed: [localhost] => (item=./conf/jaspic-providers.xml)
    changed: [localhost] => (item=conf/tomcat-users.xml)

    TASK [redhat.jws.jws : Include ajp sanity check tasks] *************************
    skipping: [localhost]

    TASK [redhat.jws.jws : Include https sanity check tasks] ***********************
    skipping: [localhost]

    TASK [redhat.jws.jws : Deploy custom configuration files] **********************
    changed: [localhost] => (item={'template': 'templates/server.xml.j2', 'dest': '/opt/jws-6.0/tomcat/./conf/server.xml'})
    changed: [localhost] => (item={'template': 'templates/web.xml.j2', 'dest': '/opt/jws-6.0/tomcat/./conf/web.xml'})
    changed: [localhost] => (item={'template': 'templates/context.xml.j2', 'dest': '/opt/jws-6.0/tomcat/./conf/context.xml'})
    changed: [localhost] => (item={'template': 'templates/catalina.properties.j2', 'dest': '/opt/jws-6.0/tomcat/./conf/catalina.properties'})

    TASK [redhat.jws.jws : Include selinux configuration tasks] ********************
    skipping: [localhost]

    TASK [redhat.jws.jws : Remove apps] ********************************************
    ok: [localhost] => (item=examples)

    TASK [redhat.jws.jws : Create vault configuration (if enabled)] ****************
    skipping: [localhost]

    TASK [redhat.jws.jws : Ensure firewalld, if enabled, allows communication over 8080.] ***
    skipping: [localhost]

    RUNNING HANDLER [redhat.jws.jws : Reload Systemd] ******************************
    ok: [localhost]

    RUNNING HANDLER [redhat.jws.jws : Ensure Jboss Web Server runs under systemd] ***
    included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/systemd/service.yml for localhost

    RUNNING HANDLER [redhat.jws.jws : Check arguments] *****************************
    ok: [localhost]

    RUNNING HANDLER [redhat.jws.jws : Enable jws.service] **************************
    changed: [localhost]

    RUNNING HANDLER [redhat.jws.jws : Start jws.service] ***************************
    changed: [localhost]

    RUNNING HANDLER [redhat.jws.jws : Restart Jboss Web Server service] ************
    changed: [localhost]

    PLAY RECAP *********************************************************************
    localhost              	: ok=65   changed=11   unreachable=0	failed=0	skipped=18   rescued=0	ignored=0   
```

Verify that the new `jws6` service is indeed up and running:

```
    # systemctl status jws6 ● jws6.service - Jboss Web Server
    Loaded: loaded (/usr/lib/systemd/system/jws6.service; enabled; vendor preset: disabled)
    Active: active (running) since Thu 2023-11-30 08:56:13 UTC; 36s ago
    Process: 2220 ExecStop=/opt/jws-6.0/tomcat/bin/systemd-service.sh stop (code=exited, status=0/SUCCESS)
    Main PID: 2261 (java)
    Tasks: 42 (limit: 1638)
    Memory: 213.1M
    CGroup: /system.slice/jws6.service └─2261 /etc/alternatives/jre_11/bin/java -Djava.util.logging.config.file=/opt/jws-6.0/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.pr>
    Nov 30 08:56:13 5e179d9cdf66 systemd[1]: Started Jboss Web Server.
    Nov 30 08:56:13 5e179d9cdf66 systemd-service.sh[2252]: Tomcat started.
    Nov 30 08:56:13 5e179d9cdf66 systemd-service.sh[2251]: Tomcat runs with PID: 2261
```

# Configuration of the JWS server

Again, for simplicity's sake, the configuration of the JWS server is rather straightforward. We only needed to define a few parameters, such as the version of the OpenJDK required to run the server and the name of the systemd service. It is, however important, to note that because both installation playbooks (JWS 5 and JWS 6) use the same vars file, their configuration will be the same. The Ansible collection for JWS supports additional features including enabling HTTPS, using Tomcat Vault, and deploying and managing native libraries. Please refer to the official documentation of the Ansible collection for Red Hat JWS.

Even if the legacy system had a more finer-grained configuration (changes in the server.xml), this can be carried over the new version as the collection supports overriding the default template used to generate for the server's configuration files:

```
    jws_conf_properties: './conf/catalina.properties' 
    jws_conf_policy: './conf/catalina.policy' 
    jws_conf_loggging: './conf/logging.properties'
    jws_conf_context: './conf/context.xml' 
    jws_conf_server: './conf/server.xml' 
    jws_conf_web: './conf/web.xml' 
    jws_conf_users: 'conf/tomcat-users.xml' 
    jws_conf_jaspic_providers: './conf/jaspic-providers.xml' jws_conf_templates_context: 'templates/context.xml.j2' 
    jws_conf_templates_server: 'templates/server.xml.j2'
```

The variables above were provided as a reference to showcase how configurations can be provided. But, for our `purposes`, we can omit their use.

# Handling failure during migration

There is another benefit of using Ansible to automate the migration to JWS 6. Ansible can also be used to ensure that the legacy system is still operational in the event of a failure at some point during the migration. Let's modify our playbook to handle such scenario:

```
    	- name: "Migrate to JWS 6"
        block:
          - name: "Install and run JWS 6"
          	ansible.builtin.include_role:
              name: redhat.jws.jws
          	vars:
              # overriding only the vars required
              jws_version: 6.0.0
              jws_service_name: jws6
              zipfile_name: jws-6.0.0-application-server.zip
        rescue:
          - name: "Restart JWS5 as migration to JWS6 failed."
          	ansible.builtin.service:
              name: jws5
              state: started
```
# Upgrade strategy

Remediation is not the only area where Ansible's feature can help the migration. Indeed, if you are migrating a large set of servers, you may not want to stop all of them at the same time. Especially, if there is a chance the migration does not always run smoothly. You may prefer to instead operate on a subset of instances, first one or two servers, to check the migration works as expected, and then another subset afterward.

Let's modify our playbook to specify the value of the serial attribute in Ansible which will implement this strategy when the the playbook runs:

```
    ---
    - name: "Migrate JWS5 to JWS6" hosts: all gather_facts: 
      no serial:
        - 1
        - 30%
        - 60%
      vars_files:
        - vars.yml pre_tasks: …
```

# Summary

In this article, we hope to have demonstrated how Ansible can both aid in the migration from one version of Red Hat JWS to another, but additionally provide an excellent framework for managing automation at scale. We have also illustrated several features of Ansible (including handling errors and execution strategy) that can be the key to a successful, smooth migration, of a large set of servers.