<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Pelisse Romain</title>
    <description>The latest articles on Forem by Pelisse Romain (@rpelisse).</description>
    <link>https://forem.com/rpelisse</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1093627%2F2a107828-904f-4562-aebd-7adbe57975b7.jpeg</url>
      <title>Forem: Pelisse Romain</title>
      <link>https://forem.com/rpelisse</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rpelisse"/>
    <language>en</language>
    <item>
      <title>Ansible Middleware : Automation of JBoss Web Server (JWS)</title>
      <dc:creator>Pelisse Romain</dc:creator>
      <pubDate>Tue, 18 Jun 2024 15:00:00 +0000</pubDate>
      <link>https://forem.com/rpelisse/ansible-middleware-automation-of-jboss-web-server-jws-5a3o</link>
      <guid>https://forem.com/rpelisse/ansible-middleware-automation-of-jboss-web-server-jws-5a3o</guid>
      <description>&lt;p&gt;In a previous article, we discussed the &lt;a href="https://open011prod.wpengine.com/2021/11/22/why-do-you-need-ansible-to-manage-your-middleware-runtimes/"&gt;importance of Ansible from a Middleware perspective&lt;/a&gt; and why making Middleware a first-class citizen in the Ansible ecosystem is crucial. In this post, we’ll explore the technical details of utilizing Ansible for automating a Middleware solution. &lt;/p&gt;

&lt;p&gt;We’ll focus on one of the most used middleware software: Apache Tomcat. Or rather, the Red Hat supported version of it known as &lt;a href="https://developers.redhat.com/products/webserver/overview"&gt;JBoss Web Server (JWS)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s start by defining what exactly JWS is, in case you are not familiar with this specific product. JWS combines a web server (Apache HTTPD), a Java servlet engine (Apache Tomcat), and load balancing components (mod_jk and mod_cluster) to help them scale. All of those elements are supported by Red Hat. In this article, we’ll focus only on the Java servlet engine (Apache Tomcat) as many of the challenges brought up by its automation are typical of other middleware software (such as JBoss EAP, JBoss Data Grid or RH SSO). &lt;/p&gt;

&lt;h2&gt;
  
  
  What are we trying to achieve?
&lt;/h2&gt;

&lt;p&gt;Our goal here is to automate the deployment of this Java servlet engine, using Ansible. This may seem like a simple endeavor. However it does entail a few tasks and operations to be performed to achieve a proper result. &lt;/p&gt;

&lt;p&gt;First, we need to &lt;strong&gt;configure the target’s operating system&lt;/strong&gt;. This includes creating a user and associate group to run JWS as well as the integration into &lt;a href="https://en.wikipedia.org/wiki/Systemd"&gt;systemd&lt;/a&gt;, so that the newly spawned server can be managed by the host’s operating system. JWS also requires that dependencies of the servlet’s engine (mostly a Java Virtual Machine in the proper version) are installed.&lt;/p&gt;

&lt;p&gt;In the next step, we'll &lt;strong&gt;configure JWS itself&lt;/strong&gt;, which includes specifying which interface it needs to be bound against, defining which ports it will listen to, and so on. We may also customize the Java server during this step, like enabling some features (ex: SSL) or disable some other ones (for instance, removing the demo webapps shipped with the archive).&lt;/p&gt;

&lt;p&gt;At this point, one could think we are done and that the server is ready. Because Apache Tomcat is an application server, however we also want to &lt;strong&gt;automate the deployment of its workloads&lt;/strong&gt;. Which means we need to ensure the webapps its hosting are appropriately deployed.&lt;/p&gt;

&lt;p&gt;With all this preparation work finished, we should be able to start the systemd service we configured earlier and double-check that the server, and its webapps, are functioning properly and as expected. This includes that all webapps are indeed deployed, accessible and operational. Here again, Ansible will help us in this &lt;strong&gt;validation step&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you are familiar with Ansible primitives and built-in modules, you know it’s quite a lot of work to automate all of these requirements. Fortunately, most of this work has been implemented and is ready for use inside the Ansible JWS Collection.&lt;/p&gt;

&lt;p&gt;An important note here: the four steps we’ve laid out above for JWS actually apply to most, if not all, middleware software (at least, the ones provided and supported by Red Hat). Some steps would be easier or more challenging to automate, depending on which one, but in essence, all will have the same kinds of requirements.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;One last thing before we jump into the technical bits: if you want to reproduce the automation we describe in this article, keep in mind that the target’s host is running RHEL 9 and uses Ansible 2.15.9 or above (with Python 3.9.18).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing the JWS Collection
&lt;/h2&gt;

&lt;p&gt;Installing the collection dedicated to Red Hat JWS uses the ansible-galaxy command like any other collection. As it is provided by Red Hat, however, it requires to use (instead or on top of Ansible Galaxy) the Red Hat Automation Hub. This can be achieved by adding the repository to the ansible.cfg file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[defaults]
...

[galaxy]
server_list = automation_hub, galaxy

[galaxy_server.galaxy]
url=https://galaxy.ansible.com/

[galaxy_server.automation_hub]
url=https://cloud.redhat.com/api/automation-hub/

auth_url=https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token

token=&amp;lt;insert-your-token-here&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More information on &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_jboss_web_server/6.0/html/installing_jboss_web_server_by_using_the_red_hat_ansible_certified_content_collection/install_collection"&gt;how to use Red Hat Automation Hub are available here&lt;/a&gt;. To &lt;a href="https://console.redhat.com/ansible/automation-hub/token"&gt;obtain the Red Hat Automation Hub token&lt;/a&gt;, follow this documentation.&lt;/p&gt;

&lt;p&gt;Once this is setup, &lt;code&gt;ansible-galaxy&lt;/code&gt;can install the collection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 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-2.0.0.tar.gz to /root/.ansible/tmp/ansible-local-91vvby1md6/tmpjzlxwbz6/redhat-jws-2.0.0-mj2vji8g
Installing 'redhat.jws:2.0.0' 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.2.1.tar.gz to /root/.ansible/tmp/ansible-local-91vvby1md6/tmpjzlxwbz6/redhat-runtimes_common-1.2.1-rwk2o0dw
redhat.jws:2.0.0 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-91vvby1md6/tmpjzlxwbz6/ansible-posix-1.5.4-adyme9vq
Installing 'redhat.runtimes_common:1.2.1' to '/root/.ansible/collections/ansible_collections/redhat/runtimes_common'
redhat.runtimes_common:1.2.1 was installed successfully
Installing 'ansible.posix:1.5.4' to '/root/.ansible/collections/ansible_collections/ansible/posix'
Downloading https://console.redhat.com/api/automation-hub/v3/plugin/ansible/content/published/collections/artifacts/redhat-rhel_system_roles-1.23.0.tar.gz to /root/.ansible/tmp/ansible-local-91vvby1md6/tmpjzlxwbz6/redhat-rhel_system_roles-1.23.0-3gm1eccc
ansible.posix:1.5.4 was installed successfully
Installing 'redhat.rhel_system_roles:1.23.0' to '/root/.ansible/collections/ansible_collections/redhat/rhel_system_roles'
redhat.rhel_system_roles:1.23.0 was installed successfully
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Ansible Galaxy comes with dependency management, which means that it fetches any required dependencies for this collection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing the playbook
&lt;/h2&gt;

&lt;p&gt;We can now start working on our playbook itself. We’ll begin by setting it up to use the collection we just installed and we’ll add content incrementally from there.&lt;br&gt;
Testing the collection&lt;/p&gt;

&lt;p&gt;Before incorporating any tasks to our playbook, we’ll add the dependency to the Ansible collection for JWS to confirm that the installation was successful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: "JBoss Web Server installation and configuration"
  hosts: "all"
  become: true
  collections:
    - redhat.jws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This playbook will not perform any tasks on the target system. It is only designed to verify that the collection is indeed recognized by Ansible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ansible-playbook -i inventory jws_dev_to.yml 

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

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

PLAY RECAP ***********************************************************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Automatically retrieve archive from Red Hat Customer Portal
&lt;/h3&gt;

&lt;p&gt;Now that the Ansible collection for JWS is properly installed and accessible from our playbook, let’s provide the service account information, so that the engine can automatically download the JWS binary files provided by Red Hat.&lt;/p&gt;

&lt;p&gt;For the collection to be able to download the JWS archive from the Red Hat Customer Portal, we need to supply the credentials associated with a Red Hat service account. One way to provide those values parameters is to create a &lt;code&gt;service_account.yml&lt;/code&gt; which can be passed to Ansible as an extra source of variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
rhn_username: &amp;lt;service_account_id&amp;gt;
rhn_password: &amp;lt;service_account_password&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; As those variables contain secrets, it is highly recommended to use Ansible Vault to protect its content. Using this feature of the automation tool, however, is out of the scope of this article.&lt;/p&gt;

&lt;p&gt;Now, we have everything in place to run our playbook and install JWS on the target. But before doing so, we will see how to configure the software to match the requirement of our use case.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ensure Java environment is properly configured
&lt;/h3&gt;

&lt;p&gt;JWS is based on Apache Tomcat which means it’s Java software that requires a Java runtime to be executed. So, our automation needs to ensure that this environment is readily available on the target system.&lt;/p&gt;

&lt;p&gt;Here again, we just need to add variables to our playbook and the Ansible Collection for JWS will take care of everything. It will check that the appropriate JVM is available or install if it’s missing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: "JBoss Web Server installation and configuration"
  hosts: "all"
  become: yes
  vars:
    jws_java_version: 17
  collections:
    – redhat.jws
  roles:
    - jws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; that this feature is only available for system belonging to the RedHat family.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible -m setup localhost | grep family
        "ansible_os_family": "RedHat",
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the target system is not part of the RedHat family, the installation of the JVM must be added to the &lt;code&gt;pre_tasks&lt;/code&gt; section of the playbook.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preparing the target system
&lt;/h3&gt;

&lt;p&gt;As we mentioned at the beginning of this article, before decompressing the archive and starting the server there are a few configurations that need to be done on target’s system. One of them is to ensure that the necessary user and group have been created.&lt;/p&gt;

&lt;p&gt;The Ansible collection for JWS comes with default values for both, but often, those would be required to be replaced:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: "JBoss Web Server installation and configuration"
  hosts: "all"
  become: yes
  vars:
    [...]
    jws_user: java_servlet_engine
    jws_group: java_web_server
    [...]
  collections:
    - redhat.jws
  roles:
    - jws
  pre_tasks:
    [...]
  tasks:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we execute this playbook, on top of fetching the archive from the website, it ensures that the appropriate group and user exists, before decompressing the servlet’s engine files into the defined &lt;code&gt;TOMCAT_HOME&lt;/code&gt;. And upon that, Ansible will guarantee the requested JVM is available on the target host.&lt;/p&gt;

&lt;p&gt;It’s already pretty nice to have all of this plumbing work done for us, but we can go further. With just a little more configuration, Ansible Collection for JWS can set up a systemd service to run JWS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integration with systemd service
&lt;/h3&gt;

&lt;p&gt;The Ansible collection for JWS comes with a playbook and default templates to help set up JWS as a &lt;code&gt;systemd&lt;/code&gt; service. Therefore, all that it’s needed to automate this part of our deployment is again to add a variable to our playbook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: "JBoss Web Server installation and configuration"
  hosts: "all"
  become: yes
  vars:
    [...]
        jws_systemd_enabled: True
    jws_service_name: tomcat
    [...]
  collections:
    - redhat.jws
  roles:
[...]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; that this feature is only available for target systems belonging to the &lt;code&gt;RedHat&lt;/code&gt; family.&lt;/p&gt;

&lt;p&gt;After a successful execution of the playbook, you can easily confirm that the Java server is running as a &lt;code&gt;systemd&lt;/code&gt; service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# systemctl status tomcat
● tomcat.service - Jboss Web Server
     Loaded: loaded (/usr/lib/systemd/system/tomcat.service; enabled; preset: disabled)
     Active: active (running) since Tue 2024-06-18 14:50:11 UTC; 52s ago
   Main PID: 3365 (java)
      Tasks: 44 (limit: 1638)
     Memory: 116.3M
        CPU: 4.170s
     CGroup: /system.slice/tomcat.service
             └─3365 /etc/alternatives/jre_17/bin/java -Djava.util.logging.config.file=/opt/jws-6.0/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogM&amp;gt;

Jun 18 14:50:11 a09c3523b337 systemd[1]: Started Jboss Web Server.
Jun 18 14:50:11 a09c3523b337 systemd-service.sh[3357]: Tomcat started.
Jun 18 14:50:11 a09c3523b337 systemd-service.sh[3356]: Tomcat runs with PID: 3365
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploy a web application
&lt;/h2&gt;

&lt;p&gt;If we come back to our list of requirements we established at the beginning of this article, we can see that the Ansible collection for JWS already took care of most of them. There is only one part of the deployment left to automate: configuring server workloads.&lt;/p&gt;

&lt;p&gt;With a different middleware solution than JWS, this part can be complex. Fortunately for us, one of the qualities of the Java server is its simplicity. Deploying webapps only necessitates placing their package file (. war) in the appropriate directory prior to the server start. That’s all!&lt;/p&gt;

&lt;p&gt;This can be easily achieved using Ansible primitives, but the collection still helps our automation by supplying a handler to restart the server is a webapp is provisioned for the first time (or updated):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: "Deploy demo webapp"
  ansible.builtin.get_url:
    url: 'https://people.redhat.com/~rpelisse/info-1.0.war'
    dest: "{{ tomcat_home }}/webapps/info.war"
  notify:
    - "Restart Tomcat service"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Validation
&lt;/h2&gt;

&lt;p&gt;Our Java server is now deployed and running, its workloads also. All that remains to be implemented is the validation part. Firing up a systemd service is good, checking that it is working is better! &lt;/p&gt;

&lt;p&gt;To achieve this, we’ll add a couple tasks to the post_tasks: section of our playbook:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check that the &lt;code&gt;systemd&lt;/code&gt; service is indeed running;&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;wait:&lt;/code&gt; task to ensure the Java server HTTP port is accessible (no need to go further if this fails);&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;get_uri:&lt;/code&gt; tasks to get the root path (/) of the server followed by another to check the webapp availability (/info) — availability of the first one not confirming the one of the second one.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[...]
tasks:
[...]
post_tasks:
   - name: "Populate service facts"
    ansible.builtin.service_facts:

   - name: "Check if service is running"
    ansible.builtin.assert:
        that:
        - ansible_facts is defined
        - ansible_facts.services is defined
        - ansible_facts.services['tomcat.service'] is defined
        - ansible_facts.services['tomcat.service']['state'] is defined
        - ansible_facts.services['tomcat.service']['state'] == 'running'
    - name: "Sleep for {{ tomcat_sleep }} seconds to let Tomcat starts "
    ansible.builtin.wait_for:
        timeout: "{{ tomcat_sleep }}"

    - name: " Checks that server is running"
      ansible.builtin.uri:
        url: "http://localhost:8080{{ item.path }}"
        status_code: {{ item.status }}
        return_content: no
     loop:
       { path: '/', status: 404 }
       { path: '/info’, status: 200 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Keeping the content of the previous article in mind, this demonstration hopefully shows how much the Ansible collection for JWS eases the automation around the Java server. Thanks to it, using Ansible, we fully automated its installation. It has been almost as simple and natural to write this playbook as it would have been for an instance of Nginx. With all this content available, we truly have made JWS a first-class citizen in the Ansible ecosystem.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>tomcat</category>
      <category>jws</category>
      <category>ansible</category>
    </item>
    <item>
      <title>Automate JBoss Web Server 6 deployment with the Red Hat Ansible Certified Content Collection for JWS</title>
      <dc:creator>Pelisse Romain</dc:creator>
      <pubDate>Thu, 15 Feb 2024 17:00:00 +0000</pubDate>
      <link>https://forem.com/rpelisse/automate-jboss-web-server-6-deployment-with-the-red-hat-ansible-certified-content-collection-for-jws-3p72</link>
      <guid>https://forem.com/rpelisse/automate-jboss-web-server-6-deployment-with-the-red-hat-ansible-certified-content-collection-for-jws-3p72</guid>
      <description>&lt;p&gt;When it comes to &lt;a href="https://developers.redhat.com/java"&gt;Java&lt;/a&gt; web servers, Apache Tomcat remains a strong favorite. Some of these instances have been containerized over the years, but many still run in the traditional setup of a &lt;a href="https://developers.redhat.com/topics/linux/"&gt;Linux&lt;/a&gt;-based virtual machine or even on bare metal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.redhat.com/products/webserver/overview"&gt;Red Hat JBoss Web Server (JWS)&lt;/a&gt; combines the servlet engine (Apache Tomcat) with the web server (Apache HTTPD), and modules for load balancing (mod_jk and mod_cluster). &lt;a href="https://www.redhat.com/en/technologies/management/ansible"&gt;Ansible&lt;/a&gt; is an automation tool that provides a suite of tools for managing an enterprise at scale.&lt;/p&gt;

&lt;p&gt;In this article, we will illustrate how &lt;a href="https://www.redhat.com/en/technologies/management/ansible"&gt;Ansible&lt;/a&gt; can be used to completely automate the deployment of a JBoss Web Server 6 instance on a &lt;a href="https://developers.redhat.com/products/rhel"&gt;Red Hat Enterprise Linux 9&lt;/a&gt; server. This automation encompasses the following tasks:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Retrieve the archive containing the JBoss Web Server from the Red Hat Customer Portal and install the files on the system.
Configure the Red Hat Enterprise Linux (RHEL) operating system including the users, groups, and the required setup files to enable JBoss Web Server as a systemd service.
Ensure the required Java Virtual Machine is installed
Fine-tune the configuration of the JBoss Web Server server, such as binding it to the appropriate interface and port.
Deploy web applications along with enabling and starting the JBoss Web Server as a [systemd](https://www.freedesktop.org/wiki/Software/systemd/) service.
Perform a health check to ensure that the deployed application is accessible.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Our Ansible playbook will fully automates all of those operations, so no manual steps will be required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing the target environment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before we start with the automation work, we need to specify the target environment. In this case, you'll be using Red Hat Enterprise Linux 9 with &lt;a href="https://developers.redhat.com/topics/python"&gt;Python 3.9&lt;/a&gt;. We'll use this configuration on both the Ansible control node (where Ansible is executed), which will be referred to from now on as &lt;strong&gt;controller&lt;/strong&gt;, and the Ansible target (the system being configured).&lt;/p&gt;

&lt;p&gt;The controller for this demonstration has the following requirements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cat /etc/redhat-release
Red Hat Enterprise Linux release 9.3 (Plow)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verifying the version of Ansible is pretty straightforward, and it also provides the needed information on the Python version used to run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$  ansible --version
ansible [core 2.14.9]
  config file = /work/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.9/site-packages/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.9.18 (main, Jan  4 2024, 00:00:00) [GCC 11.4.1 20230605 (Red Hat 11.4.1-2)] (/usr/bin/python3)
  jinja version = 3.1.2
  libyaml = True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The procedure in this article may not execute successfully if you use a different Python version or target operating system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing the Red Hat Ansible Certified Content Collection
&lt;/h3&gt;

&lt;p&gt;Once you have Red Hat Enterprise Linux 9 set up and Ansible 2.14 ready to go, you need to install the Red Hat Ansible Certified Content Collection 2.0 for Red Hat JBoss Web Server. &lt;/p&gt;

&lt;p&gt;To install the &lt;a href="https://console.redhat.com/ansible/automation-hub/repo/published/redhat/jws/"&gt;Red Hat Certified Collection for JBoss Web Server&lt;/a&gt;, you will need to configure Ansible to use Red Hat Automation Hub as the preferred &lt;a href="https://galaxy.ansible.com/"&gt;Galaxy server&lt;/a&gt;. Follow the &lt;a href="https://console.redhat.com/ansible/automation-hub/token"&gt;instructions on Automation Hub&lt;/a&gt; to retrieve your token and update the &lt;code&gt;ansible.cfg&lt;/code&gt; configuration on your Ansible controller. Update the &lt;code&gt;&amp;lt;your-token&amp;gt;&lt;/code&gt; field with the token obtained from Automation Hub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[galaxy]
server_list = automation_hub, galaxy

[galaxy_server.galaxy]
url=https://galaxy.ansible.com/

[galaxy_server.automation_hub]
url=https://cloud.redhat.com/api/automation-hub/api/galaxy/
auth_url=https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token

token=&amp;lt;your-token&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are not familiar with Ansible, note that this configuration file lives in the same directory as the Ansible playbook we are going to design for our JWS deployment. &lt;/p&gt;

&lt;p&gt;Once you have configured Ansible to use Automation Hub, install the certified collection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ 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-2.0.0.tar.gz to /root/.ansible/tmp/ansible-local-88isxfxlvv/tmpvujtdugq/redhat-jws-2.0.0-zf_lh9ed
Installing 'redhat.jws:2.0.0' 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-88isxfxlvv/tmpvujtdugq/redhat-runtimes_common-1.1.3-pf34k4r_
redhat.jws:2.0.0 was installed successfully
Installing 'redhat.runtimes_common:1.1.3' to '/root/.ansible/collections/ansible_collections/redhat/runtimes_common'
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-88isxfxlvv/tmpvujtdugq/ansible-posix-1.5.4-yie4utve
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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ansible Galaxy fetches and downloads the collection's dependencies. These dependencies include the &lt;code&gt;redhat.runtimes_common&lt;/code&gt; collection, which helps facilitate the retrieval of the archive containing the JBoss Web Server server from the Red Hat customer portal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Red Hat customer portal credentials
&lt;/h3&gt;

&lt;p&gt;For the collection to be able to download the JWS archive from the Red Hat Customer Portal, we need to supply the credentials associated with a Red Hat service account. One way to provide those values parameters is to create a &lt;code&gt;service_account.yml&lt;/code&gt; which can be passed to Ansible as an extra source of variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
rhn_username: &amp;lt;service_account_id&amp;gt;
rhn_password: &amp;lt;service_account_password&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Installing the Red Hat JBoss Web server
&lt;/h2&gt;

&lt;p&gt;The configuration steps in this section include downloading JBoss Web Server, installing Java, and enabling JBoss Web Server as a system service (systemd).&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring the JVM
&lt;/h3&gt;

&lt;p&gt;JBoss Web Server is a Java-based server, so the target system must have a Java Virtual Machine (JVM) installed. Although Ansible primitives can perform such tasks natively, the redhat.jws collection can also take care of this task as well provided that the &lt;code&gt;jws_java_version&lt;/code&gt; variable is defined. By default, the value is the latest Red Hat supported version of OpenJDK (17).&lt;/p&gt;

&lt;p&gt;While we will keep the latest version for this demonstration, note that a different version of the OpenJDK can be set using the &lt;code&gt;jws_java_version&lt;/code&gt; variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jws_java_version: 11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This feature works only if the target system's distribution belongs to the Red Hat family.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enabling JBoss Web Server as a system service (systemd)
&lt;/h3&gt;

&lt;p&gt;The JBoss Web Server server on the target system should run as a service system. The collection can also take care of this task if the jws_systemd_enabled variable is defined as True (which is the default value as the target systems are expected to be RHEL machines).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This configuration works only when systemd is installed and the system belongs to the &lt;a href="https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_conditionals.html"&gt;Red Hat family&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running the playbook
&lt;/h3&gt;

&lt;p&gt;The Red Hat Ansible Certified Content Collection comes with a playbook that can be used directly to ensure that JWS is properly installed on target instances.&lt;/p&gt;

&lt;p&gt;Execute the following command to execute playbook included within the collection along with the extra variables file created previously:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible-playbook -i inventory -e @service_account.yml redhat.jws.playbook

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 : Check for conflicting Java variables] *******************
skipping: [localhost]

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

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

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

TASK [redhat.jws.jws : Add 'openssl' and 'apr' to dependencies list required for natives (if enabled)] ***
skipping: [localhost]

TASK [redhat.jws.jws : Include tasks for Java installation (if Java version is provided)] ***
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/java_install.yml for localhost

TASK [redhat.jws.jws : Add 'java-17-openjdk-headless' to dependencies list] ****
ok: [localhost]

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

TASK [redhat.jws.jws : Install required dependencies] **************************
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost

TASK [redhat.jws.jws : Check if "zip, unzip, tzdata, sudo, java-17-openjdk-headless" packages are already installed] ***
ok: [localhost]

TASK [redhat.jws.jws : Add missing packages to the yum install list] ***********
ok: [localhost]

TASK [redhat.jws.jws : Install packages: ['java-17-openjdk-headless']] *********
changed: [localhost]

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

TASK [redhat.jws.jws : Create group: tomcat] ***********************************
changed: [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 : Set defaults values based on facts (if values not provided)] ***
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/defaults.yml for localhost

TASK [redhat.jws.jws : Set filename for JWS zipfile] ***************************
ok: [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 : Ensure patch version is specified when installing offline.] ***
skipping: [localhost]

TASK [redhat.jws.jws : Ensure credentials are defined when installing from JBossNetwork API.] ***
ok: [localhost]

TASK [redhat.jws.jws : Check main zipfile] *************************************
skipping: [localhost]

TASK [redhat.jws.jws : Check native zipfile exists] ****************************
skipping: [localhost]

TASK [redhat.jws.jws : Check patch zipfile exists] *****************************
skipping: [localhost]

TASK [redhat.jws.jws : Check native patch zipfile exists] **********************
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] =&amp;gt; {
    "msg": "Install method: zipfiles"
}

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)] ***
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/install/download_from_rhn.yml for localhost

TASK [redhat.jws.jws : Search for product to download using JBoss Network API] ***
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/rhn/search.yml for localhost

TASK [redhat.jws.jws : Ensure required parameters are provided] ****************
ok: [localhost]

TASK [redhat.jws.jws : Retrieve product download using JBossNetwork API] *******
ok: [localhost]

TASK [redhat.jws.jws : Ensure search results are valid.] ***********************
ok: [localhost]

TASK [redhat.jws.jws : Determine install zipfile from search results] **********
ok: [localhost]

TASK [redhat.jws.jws : Download Red Hat JWS] ***********************************
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/rhn/download.yml for localhost

TASK [redhat.jws.jws : Ensure required parameters are provided] ****************
ok: [localhost]

TASK [redhat.jws.jws : Load metadata on target location for download (/work/jws-6.0.0-application-server.zip)] ***
ok: [localhost]

TASK [redhat.jws.jws : Ensure /work/jws-6.0.0-application-server.zip is accessible] ***
ok: [localhost]

TASK [redhat.jws.jws : Download Red Hat product into {{ rhn_product_path }} (rhn_download_become: {{ rhn_download_become }})] ***
changed: [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-optional-native-components-RHEL9-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] =&amp;gt; (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

TASK [redhat.jws.jws : Check if "systemd, procps-ng" packages are already installed] ***
ok: [localhost]

TASK [redhat.jws.jws : Add missing packages to the yum install list] ***********
ok: [localhost]

TASK [redhat.jws.jws : Install packages: ['java-17-openjdk-headless']] *********
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-tomcat.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] =&amp;gt; (item=conf)
ok: [localhost] =&amp;gt; (item=temp)
ok: [localhost] =&amp;gt; (item=logs)
ok: [localhost] =&amp;gt; (item=webapps)
ok: [localhost] =&amp;gt; (item=bin)

TASK [redhat.jws.jws : Ensure /opt/jws-6.0/tomcat/ files have the recommended priviliges, owner and group] ***
changed: [localhost] =&amp;gt; (item=./conf/catalina.properties)
changed: [localhost] =&amp;gt; (item=./conf/catalina.policy)
changed: [localhost] =&amp;gt; (item=./conf/logging.properties)
changed: [localhost] =&amp;gt; (item=./conf/jaspic-providers.xml)
changed: [localhost] =&amp;gt; (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] =&amp;gt; (item={'template': 'templates/6/server.xml.j2', 'dest': '/opt/jws-6.0/tomcat/./conf/server.xml'})
changed: [localhost] =&amp;gt; (item={'template': 'templates/6/web.xml.j2', 'dest': '/opt/jws-6.0/tomcat/./conf/web.xml'})
changed: [localhost] =&amp;gt; (item={'template': 'templates/6/context.xml.j2', 'dest': '/opt/jws-6.0/tomcat/./conf/context.xml'})
changed: [localhost] =&amp;gt; (item={'template': 'templates/6/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] =&amp;gt; (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=66   changed=14   unreachable=0    failed=0    skipped=22   rescued=0  ignored=0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, quite a lot happened during this execution. Indeed, the &lt;code&gt;redhat.jws&lt;/code&gt; role took care of the entire setup of JWS on the target system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying a web application
&lt;/h2&gt;

&lt;p&gt;Now that JBoss Web Server is running, we will go a bit further by deploying a web application and ensuring it is running. As we’ll need to write our own playbook, the first step will be to copy the one included playbook within the collection and use it as a base:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cp ~/.ansible/collections/ansible_collections/redhat/jws/playbooks/playbook.yml .
$ cat playbook.yml
---
- name: "Red Hat JBoss Web Server installation and configuration"
  hosts: all
  become: True
  vars_files:
    - vars.yml
  roles:
    - redhat.jws.jws
$ cp ~/.ansible/collections/ansible_collections/redhat/jws/playbooks/vars.yml .
$ cat vars.yml
---
jws_setup: true
jws_java_version: 17
jws_listen_http_bind_address: 127.0.0.1
jws_systemd_enabled: True
jws_service_systemd_type: forking
jws_selinux_enabled: False
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we’ll add a tasks: section to the playbook. This section of the playbook will be run after the roles have executed successfully So, we know that JWS will be operational on the targets at this point.&lt;/p&gt;

&lt;p&gt;We will include the following tasks to perform the deployment of a web application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: "Red Hat JBoss Web Server installation and configuration"
  hosts: all
  become: True
  vars_files:
    - vars.yml
  roles:
    - redhat.jws.jws
  tasks:
    - name: "Deploy webapp"
      ansible.builtin.get_url:
       url: "https://drive.google.com/uc?export=download&amp;amp;id=1w9ss5okctnjUvRAxhPEPyC7DmbUwmbhb"
       dest: "{{ jws_home }}/webapps/info.war"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s run again the playbook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible-playbook -i inventory -e @service_account.yml playbook.yml

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

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

…

TASK [Deploy webapp] *******************************************************************************************************************
changed: [localhost]

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

PLAY RECAP *****************************************************************************************************************************
localhost               : ok=3  changed=2   unreachable=0   failed=0    skipped=0   rescued=0   ignored=0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To be thorough, we will add a &lt;code&gt;post_tasks:&lt;/code&gt; section to verify that the web application has been successfully and that the associated service is now available:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;post_tasks:
  - name: " Checks that /info is accessible"
    ansible.builtin.uri:
    url: "http://localhost:8080/info"
    status_code: 200
    return_content: no
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The benefits of such automation
&lt;/h2&gt;

&lt;p&gt;In short, automation saves time and reduces the risk of error inherent to any human manipulation.&lt;/p&gt;

&lt;p&gt;The Red Hat Ansible Certified Content Collection encapsulates (as much as possible) the complexities and the inner workings of Red Hat JBoss Web Server deployment. With the help of the certified Ansible collection, you can focus on your business use case, such as deploying applications, instead of establishing the underlying application server. The result is reduced complexity and faster time to value. The automated process is also repeatable and can be used to set up as many systems as needed&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A fully automated setup of a JBoss EAP cluster using Ansible</title>
      <dc:creator>Pelisse Romain</dc:creator>
      <pubDate>Wed, 31 Jan 2024 23:00:00 +0000</pubDate>
      <link>https://forem.com/rpelisse/a-fully-automated-setup-of-a-jboss-eap-cluster-using-ansible-4e30</link>
      <guid>https://forem.com/rpelisse/a-fully-automated-setup-of-a-jboss-eap-cluster-using-ansible-4e30</guid>
      <description>&lt;h2&gt;
  
  
  Foreword
&lt;/h2&gt;

&lt;p&gt;This article assumes that you have prior knowledge of both Ansible and the steps associated with a basic installation of Red Hat JBoss Enterprise Application Platform (JBoss EAP)/WildFly. Visit the Ansible courses page to learn the fundamentals of using Ansible.&lt;/p&gt;

&lt;p&gt;An earlier article already covered this topic. However, this article provides a much needed update to its content; particularly documenting how to use the Red Hat Ansible Certified Content Collection for JBoss EAP (redhat.eap) instead of the community version of the collection (middleware_automation.wildfly).&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The objective of this demonstration is to set up and run three JBoss EAP instances forming a cluster. In this context, the application servers must communicate with each other to synchronize the content of the applications' session. This configuration guarantees that, if one instance fails while processing a request, another one can pick up the work without any data loss. In short, an EAP cluster is strategy to ensure high availability of the apps executed by the JEE server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use case: Deploying a JBoss EAP cluster with Ansible
&lt;/h2&gt;

&lt;p&gt;Note that, for simplicity’s sake, we’ll use &lt;a href="https://en.wikipedia.org/wiki/Multicast"&gt;multicast&lt;/a&gt; discovery to identify members of the cluster and assure that the cluster’s formation is fully &lt;a href="https://developers.redhat.com/topics/automation/"&gt;automated&lt;/a&gt; and dynamic. This will allow the cluster to configure itself without additional configuration. It’s worth mentioning that this setup can also work without multicast, but it is not the intended focus of this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;The first step is to install Ansible on the workstation, which will be referred to from now on as the Ansible control node along with ensuring that the tool can connect to the target systems. The process for setting up Ansible is out of scope for this article, but do refer to the Ansible documentation to perform this installation (keeping in mind that Ansible version 2.14 or above is recommended).&lt;/p&gt;

&lt;p&gt;The second prerequisite is to provide the appropriate token to Ansible so that it can interact with Ansible automation hub to download the &lt;code&gt;redhat.eap&lt;/code&gt; collection. Refer to the &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_ansible_automation_platform/2.4/html-single/getting_started_with_automation_hub/index"&gt;Red Hat Ansible documentation&lt;/a&gt; for this step.&lt;/p&gt;

&lt;p&gt;Once the content of the &lt;code&gt;ansible.cfg&lt;/code&gt; has been properly configured to use Ansible automation hub, the last step consists of installing the Red Hat Ansible Certified Content Collection for JBoss EAP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ansible-galaxy collection install redhat.eap
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-eap-1.4.3.tar.gz to /root/.ansible/tmp/ansible-local-37nv77u54f/tmp3t3je__p/redhat-eap-1.4.3-wo61xl4t
Installing 'redhat.eap:1.4.3' to '/root/.ansible/collections/ansible_collections/redhat/eap'
redhat.eap:1.4.3 was installed successfully
'ansible.posix:1.5.4' is already installed, skipping.
'redhat.runtimes_common:1.1.3' is already installed, skipping.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the collection to be able to download the JBoss EAP archives from the Red Hat Customer Portal, we need to supply the credentials tied a Red HAT service account. One way to provide those values parameters is to create a &lt;a href="https://console.redhat.com/application-services/service-accounts"&gt;service_account.yml&lt;/a&gt; which can be passed to Ansible as an extra source of variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
rhn_username: &amp;lt;service_account_id&amp;gt;
rhn_password: &amp;lt;service_account_password&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; We could use &lt;a href="https://docs.ansible.com/ansible/latest/vault_guide/index.html"&gt;Ansible's vault&lt;/a&gt; to safely encrypt the credential values, but doing that is out of the scope of this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up the JBoss EAP cluster
&lt;/h2&gt;

&lt;p&gt;A typical JBoss EAP cluster has many machines, each operating a dedicated instance. For the simplicity of testing and ensuring reproducibility on a development system, we are going to use just one server to run several instances of JBoss EAP. Using the Red Hat Ansible Certified Content Collection for JBoss EAP, constructing this type of architecture is relatively easy, as the collection provides all the required plumbing.&lt;/p&gt;

&lt;p&gt;The process we are going to automate thanks to Ansible (and the &lt;code&gt;redhat.eap&lt;/code&gt; collection) consists of two parts:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Install JBoss EAP on the hosts. This installation involves authenticating against the Red Hat Customer portal and downloading the EAP 7.4 archive prior to decompressing it in the appropriate directory (`JBOSS_HOME`). All of this is facilitated by the `eap_install` role within the `redhat.eap` collection.

Create the configuration files required to run several instances of JBoss EAP on the same host. Because we're executing multiple instances on a single machine, we need to ensure that each instance has its own subdirectories and set of ports so that they can coexist and communicate with each other. Fortunately, this functionality is also provided by a role within the Ansible collection called `eap_systemd`.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Ansible playbook to install JBoss EAP
&lt;/h2&gt;

&lt;p&gt;Here is our Ansible playbook for installing and configuring JBoss EAP:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: "JBoss EAP installation and configuration"
  hosts: "{{ hosts_group_name | default('localhost') }}"
  become: yes
  vars:
    eap_install_workdir: '/opt'
    eap_version: '7.4.0'
    install_name: jboss-eap
    eap_user: "{{ install_name }}"
    eap_config_base: standalone-ha.xml
    eap_home: "{{ eap_install_workdir }}/{{ install_name }}-{{ (eap_version.split('.'))[0:2] | join('.') }}"

    instance_http_ports:
      - 8080
      - 8180
      - 8280
    app:
      name: 'info-1.1.war'
      url: 'https://drive.google.com/uc?export=download&amp;amp;id=1w9ss5okctnjUvRAxhPEPyC7DmbUwmbhb'
  collections:
    - redhat.eap
  roles:
    - eap_install
  tasks:

    - name: "Set up for WildFly instance {{ item }}"
      include_role:
        name: eap_systemd
      vars:
        eap_config_base: 'standalone-ha.xml'
        eap_basedir_prefix: "/opt/{{ inventory_hostname }}"
        eap_config_name: "{{ install_name }}"
        eap_instance_name: "{{ install_name }}"
        eap_instance_id: "{{ item }}"
        service_systemd_env_file: "/etc/eap-{{ item }}.conf"
        service_systemd_conf_file: "/usr/lib/systemd/system/jboss-eap-{{ item }}.service"
      loop: "{{ range(0,3) | list }}"
  post_tasks:

    - set_fact:
            instance_http_ports:
                - 8080
                - 8180
                - 8280
    - wait_for:
        port: "{{ item }}"
      loop: "{{ instance_http_ports }}"

    - name: "Checks that WildFly server is running and accessible"
      get_url:
        url: "http://localhost:{{ item }}/"
        dest: '/dev/null'
      loop: "{{ instance_http_ports }}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the playbook&lt;/p&gt;

&lt;p&gt;Now, let’s run our Ansible playbook and check the resulting output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible-playbook -i inventory -e @service_account.yml eap-cluster.yml
PLAY [JBoss EAP installation and configuration] ********************************

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

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

TASK [redhat.eap.eap_install : Ensure prerequirements are fullfilled.] *********
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_install/tasks/prereqs.yml for localhost

TASK [redhat.eap.eap_install : Validate credentials] ***************************
ok: [localhost]

TASK [redhat.eap.eap_install : Validate existing zipfiles jboss-eap-7.4.0.zip for offline installs] ***
skipping: [localhost]

TASK [redhat.eap.eap_install : Validate patch version for offline installs] ****
skipping: [localhost]

TASK [redhat.eap.eap_install : Validate existing additional zipfiles jboss-eap-7.4.0.zip for offline installs] ***
skipping: [localhost]

TASK [redhat.eap.eap_install : Check that required packages list has been provided.] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Prepare packages list] **************************
skipping: [localhost]

TASK [redhat.eap.eap_install : Add JDK package java-11-openjdk-headless to packages list] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Install required packages (5)] ******************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure required local user exists.] *************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_install/tasks/user.yml for localhost

TASK [redhat.eap.eap_install : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Set eap group] **********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure group jboss-eap exists.] *****************
changed: [localhost]

TASK [redhat.eap.eap_install : Ensure user jboss-eap exists.] ******************
changed: [localhost]

TASK [redhat.eap.eap_install : Ensure workdir /opt exists.] ********************
changed: [localhost]

TASK [redhat.eap.eap_install : Ensure archive_dir /opt exists.] ****************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure server is installed] *********************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_install/tasks/install.yml for localhost

TASK [redhat.eap.eap_install : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Check local download archive path] **************
ok: [localhost]

TASK [redhat.eap.eap_install : Set download paths] *****************************
ok: [localhost]

TASK [redhat.eap.eap_install : Check target archive: /opt/jboss-eap-7.4.0.zip] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Retrieve archive from website: https://github.com/eap/eap/releases/download] ***
skipping: [localhost]

TASK [redhat.eap.eap_install : Retrieve archive from RHN] **********************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_install/tasks/install/rhn.yml for localhost

TASK [redhat.eap.eap_install : Check arguments] ********************************
ok: [localhost]

TASK [Download JBoss EAP from CSP] *********************************************

TASK [redhat.eap.eap_utils : Check arguments] **********************************
ok: [localhost]

TASK [redhat.eap.eap_utils : Retrieve product download using JBoss Network API] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Determine install zipfile jboss-eap-7.4.0.zip from search results.] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Verify that filtered products has been properly populated.] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Download Red Hat JBoss Enterprise Application Platform] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Install server using RPM] ***********************
skipping: [localhost]

TASK [redhat.eap.eap_install : Check downloaded archive] ***********************
ok: [localhost]

TASK [redhat.eap.eap_install : Copy archive to target nodes] *******************
changed: [localhost]

TASK [redhat.eap.eap_install : Check target archive: /opt/jboss-eap-7.4.0.zip] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Verify target archive state: /opt/jboss-eap-7.4.0.zip] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Read target directory information: /opt/jboss-eap-7.4] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Extract files from /opt/jboss-eap-7.4.0.zip into /opt.] ***
changed: [localhost]

TASK [redhat.eap.eap_install : Note: decompression was not executed] ***********
skipping: [localhost]

TASK [redhat.eap.eap_install : Read information on server home directory: /opt/jboss-eap-7.4] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Check state of server home directory: /opt/jboss-eap-7.4] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Set instance name] ******************************
ok: [localhost]

TASK [redhat.eap.eap_install : Deploy custom configuration] ********************
skipping: [localhost]

TASK [redhat.eap.eap_install : Deploy configuration] ***************************
changed: [localhost]

TASK [Apply latest cumulative patch] *******************************************

TASK [redhat.eap.eap_utils : Check installation] *******************************
ok: [localhost]

TASK [redhat.eap.eap_utils : Set patch directory] ******************************
ok: [localhost]

TASK [redhat.eap.eap_utils : Set download patch archive path] ******************
skipping: [localhost]

TASK [redhat.eap.eap_utils : Check download patch archive path] ****************
skipping: [localhost]

TASK [redhat.eap.eap_utils : Check local download archive path] ****************
ok: [localhost]

TASK [redhat.eap.eap_utils : Check local downloaded archive: {{ patch_bundle }}] ***
skipping: [localhost]

TASK [redhat.eap.eap_utils : Retrieve product download using JBossNetwork API] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Determine patch versions list] ********************
ok: [localhost]

TASK [redhat.eap.eap_utils : Determine latest version] *************************
ok: [localhost]

TASK [redhat.eap.eap_utils : Determine install zipfile from search results] ****
ok: [localhost]

TASK [redhat.eap.eap_utils : Determine selected patch from supplied version: {{ eap_patch_version }}] ***
skipping: [localhost]

TASK [redhat.eap.eap_utils : Check remote downloaded archive: /opt/jboss-eap-7.4.13-patch.zip] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Download Red Hat EAP patch] ***********************
ok: [localhost]

TASK [redhat.eap.eap_utils : Update patch archive path after download] *********
ok: [localhost]

TASK [redhat.eap.eap_utils : Check remote download patch archive path] *********
ok: [localhost]

TASK [redhat.eap.eap_utils : Copy patch archive to target nodes] ***************
changed: [localhost]

TASK [redhat.eap.eap_utils : Check patch state] ********************************
ok: [localhost]

TASK [redhat.eap.eap_utils : Set checksum file path for patch] *****************
ok: [localhost]

TASK [redhat.eap.eap_utils : Check /opt/jboss-eap-7.4/.applied_patch_checksum_6427fed0a0fab256a058232c1aa02efcdb32919d.txt state] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Print when patch has been applied already] ********
skipping: [localhost]

TASK [redhat.eap.eap_utils : Check if management interface is reachable] *******
fatal: [localhost]: FAILED! =&amp;gt; {"changed": false, "elapsed": 1, "msg": "Timeout when waiting for localhost:9990"}

TASK [redhat.eap.eap_utils : Set instance name] ********************************
skipping: [localhost]

TASK [redhat.eap.eap_utils : Deploy configuration] *****************************
ok: [localhost]

TASK [redhat.eap.eap_utils : Start eap for patching] ***************************
changed: [localhost]

TASK [redhat.eap.eap_utils : Wait for management interface is reachable] *******
ok: [localhost]

TASK [redhat.eap.eap_utils : Set apply CP conflict default strategy to default (if not defined): --override-all] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Apply patch /opt/jboss-eap-7.4.13-patch.zip to server installed in /opt/jboss-eap-7.4] ***
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_utils/tasks/jboss_cli.yml for localhost

TASK [redhat.eap.eap_utils : Ensure required params for JBoss CLI have been provided] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Ensure server's management interface is reachable] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Execute CLI query 'patch apply --override-all /opt/jboss-eap-7.4.13-patch.zip'] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Display patching result] **************************
ok: [localhost] =&amp;gt; {
    "msg": "Apply patch operation result: {\n    \"outcome\" : \"success\",\n    \"response-headers\" : {\n        \"operation-requires-restart\" : true,\n        \"process-state\" : \"restart-required\"\n    }\n}"
}

TASK [redhat.eap.eap_utils : Set checksum file] ********************************
changed: [localhost]

TASK [redhat.eap.eap_utils : Set latest patch file] ****************************
changed: [localhost]

TASK [redhat.eap.eap_utils : Restart server to ensure patch content is running] ***
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_utils/tasks/jboss_cli.yml for localhost

TASK [redhat.eap.eap_utils : Ensure required params for JBoss CLI have been provided] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Ensure server's management interface is reachable] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Execute CLI query 'shutdown --restart'] ***********
ok: [localhost]

TASK [redhat.eap.eap_utils : Wait for management interface is reachable] *******
ok: [localhost]

TASK [redhat.eap.eap_utils : Stop service if it was started for patching] ******
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_utils/tasks/jboss_cli.yml for localhost

TASK [redhat.eap.eap_utils : Ensure required params for JBoss CLI have been provided] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Ensure server's management interface is reachable] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Execute CLI query 'shutdown'] *********************
ok: [localhost]

TASK [redhat.eap.eap_utils : Display resulting output] *************************
skipping: [localhost]

TASK [redhat.eap.eap_install : Ensure required parameters for elytron adapter are provided.] ***
skipping: [localhost]

TASK [Install elytron adapter] *************************************************
skipping: [localhost]

TASK [redhat.eap.eap_install : Install server using Prospero] ******************
skipping: [localhost]

TASK [redhat.eap.eap_install : Check eap install directory state] **************
ok: [localhost]

TASK [redhat.eap.eap_install : Validate conditions] ****************************
ok: [localhost]

TASK [Ensure firewalld configuration allows server port (if enabled).] *********
skipping: [localhost]

TASK [Set up for WildFly instance {{ item }}] **********************************

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

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Check current EAP patch installed] **************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check arguments for yaml configuration] *********
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check if YAML configuration extension is supported in WildFly] ***
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check if YAML configuration extension is supported in EAP] ***
skipping: [localhost]

TASK [Ensure required local user and group exists.] ****************************

TASK [redhat.eap.eap_install : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Set eap group] **********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure group jboss-eap exists.] *****************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure user jboss-eap exists.] ******************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set destination directory for configuration] ****
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set instance destination directory for configuration] ***
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set base directory for instance] ****************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
ok: [localhost] =&amp;gt; {
    "changed": false,
    "msg": "All assertions passed"
}

TASK [redhat.eap.eap_systemd : Set instance name] ******************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set instance name] ******************************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set bind address] *******************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Create basedir /opt/localhost0 for instance: jboss-eap-0] ***
changed: [localhost]

TASK [redhat.eap.eap_systemd : Create deployment directories for instance: jboss-eap-0] ***
changed: [localhost]

TASK [redhat.eap.eap_systemd : Deploy custom configuration] ********************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Deploy configuration] ***************************
changed: [localhost]

TASK [redhat.eap.eap_systemd : Include YAML configuration extension] ***********
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check YAML configuration is disabled] ***********
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set systemd envfile destination] ****************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Determine JAVA_HOME for selected JVM] ***********
ok: [localhost]

TASK [redhat.eap.eap_systemd : Determine JAVA_HOME for selected JVM] ***********
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set systemd unit file destination] **************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Deploy service instance configuration: /etc/eap-0.conf] ***
changed: [localhost]

TASK [redhat.eap.eap_systemd : Deploy Systemd configuration for service: /usr/lib/systemd/system/jboss-eap-0.service] ***
changed: [localhost]

TASK [redhat.eap.eap_systemd : Perform daemon-reload to ensure the changes are picked up] ***
ok: [localhost]

TASK [redhat.eap.eap_systemd : Ensure service is started] **********************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_systemd/tasks/service.yml for localhost

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set instance jboss-eap-0 state to started] ******
changed: [localhost]

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

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Check current EAP patch installed] **************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check arguments for yaml configuration] *********
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check if YAML configuration extension is supported in WildFly] ***
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check if YAML configuration extension is supported in EAP] ***
skipping: [localhost]

TASK [Ensure required local user and group exists.] ****************************

TASK [redhat.eap.eap_install : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Set eap group] **********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure group jboss-eap exists.] *****************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure user jboss-eap exists.] ******************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set destination directory for configuration] ****
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set instance destination directory for configuration] ***
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set base directory for instance] ****************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
ok: [localhost] =&amp;gt; {
    "changed": false,
    "msg": "All assertions passed"
}

TASK [redhat.eap.eap_systemd : Set instance name] ******************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set instance name] ******************************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set bind address] *******************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Create basedir /opt/localhost1 for instance: jboss-eap-1] ***
changed: [localhost]

TASK [redhat.eap.eap_systemd : Create deployment directories for instance: jboss-eap-1] ***
changed: [localhost]

TASK [redhat.eap.eap_systemd : Deploy custom configuration] ********************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Deploy configuration] ***************************
changed: [localhost]

TASK [redhat.eap.eap_systemd : Include YAML configuration extension] ***********
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check YAML configuration is disabled] ***********
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set systemd envfile destination] ****************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Determine JAVA_HOME for selected JVM] ***********
ok: [localhost]

TASK [redhat.eap.eap_systemd : Determine JAVA_HOME for selected JVM] ***********
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set systemd unit file destination] **************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Deploy service instance configuration: /etc/eap-1.conf] ***
changed: [localhost]

TASK [redhat.eap.eap_systemd : Deploy Systemd configuration for service: /usr/lib/systemd/system/jboss-eap-1.service] ***
changed: [localhost]

TASK [redhat.eap.eap_systemd : Perform daemon-reload to ensure the changes are picked up] ***
ok: [localhost]

TASK [redhat.eap.eap_systemd : Ensure service is started] **********************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_systemd/tasks/service.yml for localhost

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set instance jboss-eap-1 state to started] ******
changed: [localhost]

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

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Check current EAP patch installed] **************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check arguments for yaml configuration] *********
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check if YAML configuration extension is supported in WildFly] ***
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check if YAML configuration extension is supported in EAP] ***
skipping: [localhost]

TASK [Ensure required local user and group exists.] ****************************

TASK [redhat.eap.eap_install : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Set eap group] **********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure group jboss-eap exists.] *****************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure user jboss-eap exists.] ******************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set destination directory for configuration] ****
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set instance destination directory for configuration] ***
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set base directory for instance] ****************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
ok: [localhost] =&amp;gt; {
    "changed": false,
    "msg": "All assertions passed"
}

TASK [redhat.eap.eap_systemd : Set instance name] ******************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set instance name] ******************************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set bind address] *******************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Create basedir /opt/localhost2 for instance: jboss-eap-2] ***
changed: [localhost]

TASK [redhat.eap.eap_systemd : Create deployment directories for instance: jboss-eap-2] ***
changed: [localhost]

TASK [redhat.eap.eap_systemd : Deploy custom configuration] ********************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Deploy configuration] ***************************
changed: [localhost]

TASK [redhat.eap.eap_systemd : Include YAML configuration extension] ***********
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check YAML configuration is disabled] ***********
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set systemd envfile destination] ****************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Determine JAVA_HOME for selected JVM] ***********
ok: [localhost]

TASK [redhat.eap.eap_systemd : Determine JAVA_HOME for selected JVM] ***********
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set systemd unit file destination] **************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Deploy service instance configuration: /etc/eap-2.conf] ***
changed: [localhost]

TASK [redhat.eap.eap_systemd : Deploy Systemd configuration for service: /usr/lib/systemd/system/jboss-eap-2.service] ***
changed: [localhost]

TASK [redhat.eap.eap_systemd : Perform daemon-reload to ensure the changes are picked up] ***
ok: [localhost]

TASK [redhat.eap.eap_systemd : Ensure service is started] **********************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_systemd/tasks/service.yml for localhost

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set instance jboss-eap-2 state to started] ******
changed: [localhost]

TASK [set_fact] ****************************************************************
ok: [localhost]

TASK [wait_for] ****************************************************************
ok: [localhost] =&amp;gt; (item=8080)
ok: [localhost] =&amp;gt; (item=8180)
ok: [localhost] =&amp;gt; (item=8280)

TASK [Checks that WildFly server is running and accessible] ********************
ok: [localhost] =&amp;gt; (item=8080)
ok: [localhost] =&amp;gt; (item=8180)
ok: [localhost] =&amp;gt; (item=8280)

PLAY RECAP *********************************************************************
localhost                  : ok=145  changed=28   unreachable=0    failed=0    skipped=52   rescued=1    ignored=0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although the playbook is quite short, it performs quite a lot of tasks (around one hundred and fifty tasks). First, the &lt;code&gt;eap_install&lt;/code&gt; role uses the provided credentials to connect to Red Hat Customer Portal and download the &lt;code&gt;jboss-eap-7.4.zip&lt;/code&gt; archive. Ansible then ensures that the target system has all the required prerequisite (user accounts and dedicated group, system dependencies, …). And, finally, the product files are installed in the appropriate folders by decompressing the archive.&lt;/p&gt;

&lt;p&gt;After that, the &lt;code&gt;eap_systemd&lt;/code&gt; role that will take care of setting up three distinct systemd services, one for each JBoss EAP instance running on the target system. A nice benefit of this approach is that the binary file of JBoss EAP are not duplicated. All the product files live in the &lt;code&gt;/opt/jboss-eap-74&lt;/code&gt; directory. The only files or directories replicated are the ones that are tied to one of the instances. It also means that, in order to update all the instances (to a newly released minor version of EAP), one only needs to update the files located in this folder.&lt;/p&gt;

&lt;p&gt;On top of everything, the instances have already been configured to use the &lt;code&gt;standalone-ha.xml&lt;/code&gt; configuration as the baseline, so they are, already, set up for clustering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify that JBoss EAP instances and associated services are running
&lt;/h2&gt;

&lt;p&gt;The playbook confirms that each instance can be reached through its own HTTP port. We can also verify that the services are running by using the &lt;code&gt;systemctl&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# systemctl status jboss-eap-*
● jboss-eap-0.service - JBoss EAP (standalone mode)
   Loaded: loaded (/usr/lib/systemd/system/jboss-eap-0.service; enabled; vendor preset: disabled)
   Active: active (running) since Thu 2021-12-23 12:31:41 UTC; 1min 55s ago
 Main PID: 1138 (standalone.sh)
    Tasks: 70 (limit: 1638)
   Memory: 532.3M
   CGroup: /system.slice/jboss-eap-0.service
           ├─1138 /bin/sh /opt/jboss-eap-7.4/bin/standalone.sh -c jboss-eap-0.xml -b 0.0.0.0 -Djboss.server.con&amp;gt;
           └─1261 java -D[Standalone] -server -verbose:gc -Xloggc:/opt/localhost0/log/gc.log -XX:+PrintGCDetail&amp;gt;
Dec 23 12:31:44 7b38800644ee standalone.sh[1138]: 12:31:44,548 INFO  [org.jboss.as.patching] (MSC service thread)
Dec 23 12:31:44 7b38800644ee standalone.sh[1138]: 12:31:44,563 WARN  [org.jboss.as.domain.management.security] &amp;gt;
Dec 23 12:31:44 7b38800644ee standalone.sh[1138]: 12:31
…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy an application to the JBoss EAP cluster&lt;/p&gt;

&lt;p&gt;At this point, the three JBoss EAP instances are running and configured to form a cluster. As no application has deployed, however, the cluster is not yet active (there is no data that would require some sort of synchronization between the instances).&lt;/p&gt;

&lt;p&gt;We are going to modify our Ansible playbook to deploy of an application in each of the three JBoss EAP instances. To do so, we’ll leverage another feature of the Red Hat Ansible Certified Content Collection for JBoss EAP (redhat.eap) that integrate the use of the JBoss command-line tool (&lt;code&gt;jboss-cli&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;…
    - name: "Ensures webapp {{ app.name }} has been retrieved from {{ app.url }}"
      get_url:
        url: "{{ app.url }}"
        dest: "{{ wildfly_install_workdir }}/{{ app.name }}"

    - name: "Deploy webapp"
      include_role:
        name: jboss_eap
        tasks_from: jboss_cli.yml
      vars:
        jboss_home: "{{ wildfly_home }}"
        query: "'deploy --force {{ wildfly_install_workdir }}/{{ app.name }}'"
        jboss_cli_controller_port: "{{ item }}"
      loop:
        - 10090
        - 10190
        - 10290
…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s execute again the playbook so that the web application is deployed on all instances. Once the automation completes successfully, the deployment of this application will trigger the formation of the cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify the JBoss EAP cluster and application deployment
&lt;/h2&gt;

&lt;p&gt;You can verify the JBoss EAP cluster formation by looking at the log files of any of the three JBoss EAP instances:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ grep -e 'Received new cluster view for channel ejb:' /opt/jboss-eap-7.4/standalone/log/server.log
…

2023-11-23 15:02:08,252 INFO  [org.infinispan.CLUSTER] (thread-7,ejb,jboss-eap-0) ISPN000094: Received new cluster view for channel ejb: [jboss-eap-0] (3) [jboss-eap-0, jboss-eap-1, jboss-eap-2]
…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To be thorough, you can also check that the application is properly deployed and accessible. To validate the application's operation, we can simply add a separate Ansible playbook called &lt;code&gt;validate.yml&lt;/code&gt;. We can then use this new playbook into our &lt;code&gt;playbook.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;post_tasks:
  - include_tasks: validate.yml
    loop: "{{ instance_http_ports }}"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;validate.yml&lt;/code&gt; file contains the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---

- ansible.builtin.assert:
    that:
      - item is defined

- ansible.builtin.wait_for:
    port: "{{ item }}"

- name: "Checks that WildFly server is running and accessible on port {{ item }}"
  ansible.builtin.get_url:
    url: "http://localhost:{{ item }}/"
    dest: '/dev/null'
  changed_when: False

- ansible.builtin.include_tasks: info.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This playbook includes another one, called info.yml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- ansible.builtin.assert:
    that:
      - item is defined
    quiet: true

- ansible.builtin.set_fact:
    result_file: "/tmp/info-{{ item }}.txt"

- ansible.builtin.get_url:
    url: "http://localhost:{{ item }}/info/"
    dest: "{{ result_file }}"
  changed_when: False

- ansible.builtin.slurp:
    src: "{{ result_file }}"
  register: info_res

- ansible.builtin.debug:
    msg: "{{ info_res['content'] | b64decode }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To complete the exercise, we can run the validation playbook and see whether it confirms that our setup is fully functional:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TASK [get_url] ********************************************************************************
changed: [localhost]

TASK [slurp] **********************************************************************************
ok: [localhost]

TASK [debug] **********************************************************************************
ok: [localhost] =&amp;gt; {
    "msg": "Request received&amp;lt;br/&amp;gt;Requested URL:\t\t\thttp://localhost:8380/info/&amp;lt;br/&amp;gt;Runs on node:\t\t\tda953ac17443 [IP: 10.0.2.100 ]&amp;lt;br/&amp;gt;Requested by:\t\t\t127.0.0.1 [IP: 127.0.0.1, port: 40334 ]&amp;lt;br/&amp;gt;JBOSS_ID:\t\t\tnull&amp;lt;br/&amp;gt;"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We've illustrated how to fully automated the setup and configuration of a three-instance cluster of JBoss EAP, along with the deployment of an application. The playbook is simple and straightforward. Most importantly, we were able to focus primarily on deploying the application. The Red Hat Ansible Certified Content Collection for JBoss EAP included all the required plumbing needed and did the heavy lifting, with little input by the end user.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>ansible</category>
      <category>jboss</category>
      <category>java</category>
    </item>
    <item>
      <title>Deploying a WildFly 30.0.1.Final cluster using Ansible</title>
      <dc:creator>Pelisse Romain</dc:creator>
      <pubDate>Thu, 18 Jan 2024 17:00:00 +0000</pubDate>
      <link>https://forem.com/rpelisse/deploying-a-wildfly-3001final-cluster-using-ansible-5e0</link>
      <guid>https://forem.com/rpelisse/deploying-a-wildfly-3001final-cluster-using-ansible-5e0</guid>
      <description>&lt;p&gt;In this brief demonstration, we’ll set up and run three instances of WildFly on the same machine (localhost). Together they will form a cluster. It’s a rather classic setup, where the appservers needs to synchronize the content of their application’s session to ensure fail over if one of the instances fails. This configuration guarantees that, if one instance fails while processing a request, another one can pick up the work without any data loss. Note that we’ll use a multicast to discover the members of the cluster and ensure that the cluster’s formation is fully automated and dynamic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Ansible and its collection for WildFly
&lt;/h2&gt;

&lt;p&gt;On a Linux system using a package manager, installing Ansible is pretty straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo dnf install ansible-core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please refer to the documentation available online for installation on other operating system. Note that this demonstration assumes you are running both the Ansible controller and the target (same machine in our case) on a Linux system. However, it should work on any other operating system with a few adjustements.&lt;/p&gt;

&lt;p&gt;Before going further, double check that you are running a recent enough version of Ansible (2.14 or above will do):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible --version
ansible [core 2.14.1]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/rpelisse/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.11/site-packages/ansible
  ansible collection location = /home/rpelisse/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.11.0 (main, Oct 24 2022, 00:00:00) [GCC 12.2.1 20220819 (Red Hat 12.2.1-2)] (/usr/bin/python3)
  jinja version = 3.0.3
  libyaml = True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next, and last, step to ready your Ansible environment is to install the Ansible collection for WildFly on the controller (the machine that will run Ansible):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible --version
ansible [core 2.14.1]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/rpelisse/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.11/site-packages/ansible
  ansible collection location = /home/rpelisse/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.11.0 (main, Oct 24 2022, 00:00:00) [GCC 12.2.1 20220819 (Red Hat 12.2.1-2)] (/usr/bin/python3)
  jinja version = 3.0.3
  libyaml = True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Set up the WildFly cluster
&lt;/h2&gt;

&lt;p&gt;For simplicity’s sake and to allow you to reproduce this demonstration on a single machine (physical or virtual) or even a container, we opted to deploy our three instances on one target. We chose localhost as a target, so that the demonstration can even be performed without a remote host.&lt;/p&gt;

&lt;p&gt;There are essentially two steps to set up the WildFly cluster:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Install WildFly on the targeted hosts (here just localhost). This means downloading the archive from this website and decompressing the archive in the appropriate directory (JBOSS_HOME). These tasks are handled by the wildfly_install role supplied by Ansible collection for WildFly.

Create the configuration files to run several instances of WildFly. Because we’re running multiple instances on a single host, you also need to ensure that each instance has its own subdirectories and set of ports, so that the instances can coexist and communicate. Fortunately, this functionality is provided by a role within the Ansible collection called wildfly_systemd.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Ansible playbook to install WildFly
&lt;/h2&gt;

&lt;p&gt;Here is the playbook we’ll use to deploy our clusters. Its content is relatively self-explanitory, at least if you are somewhat familiar with the Ansible syntax.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: "WildFly installation and configuration"
  hosts: "{{ hosts_group_name | default('localhost') }}"
  become: yes
  vars:
    wildfly_install_workdir: '/opt/'
    wildfly_config_base: standalone-ha.xml
    wildfly_version: 30.0.1.Final
    wildfly_java_package_name: java-11-openjdk-headless.x86_64
    wildfly_home: "/opt/wildfly-{{ wildfly_version }}"

    instance_http_ports:
      - 8080
      - 8180
      - 8280
    app:
      name: 'info-1.2.war'
      url: 'https://drive.google.com/uc?export=download&amp;amp;id=13K7RCqccgH4zAU1RfOjYMehNaHB0A3Iq'
  collections:
    - middleware_automation.wildfly
  roles:
    - role: wildfly_install
  tasks:

    - name: "Set up for WildFly instance {{ item }}."
      ansible.builtin.include_role:
        name: wildfly_systemd
      vars:
        wildfly_config_base: 'standalone-ha.xml'
        wildfly_instance_id: "{{ item }}"
        instance_name: "wildfly-{{ wildfly_instance_id }}"
        wildfly_config_name: "{{ instance_name }}.xml"
        wildfly_basedir_prefix: "/opt/{{ instance_name }}"
        service_systemd_env_file: "/etc/wildfly-{{ item }}.conf"
        service_systemd_conf_file: "/usr/lib/systemd/system/wildfly-{{ item }}.service"
      loop: "{{ range(0,3) | list }}"

    - name: "Wait for each instance HTTP ports to become available."
      ansible.builtin.wait_for:
        port: "{{ item }}"
      loop: "{{ instance_http_ports }}"

    - name: "Checks that WildFly server is running and accessible."
      ansible.builtin.get_url:
        url: "http://localhost:{{ port }}/"
        dest: "/opt/{{ port }}"
      loop: "{{ instance_http_ports }}"
      loop_control:
        loop_var: port
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In short, this playbook uses the Ansible collection for WildFly to, first, install the appserver by using the wildfly_install role. This will download all the artifacts, create the required system groups and users, install dependency (unzip) and so on. At the end of its execution, all the tidbits required to run WildFly on the target host are installed, but the server is not yet running. That’s what happening in the next step.&lt;/p&gt;

&lt;p&gt;In the tasks section of the playbook, we then call on another role provided by the collection: wildfly_systemd. This role will take care of integrating WildFly, as a regular system service, into the service manager. Here, we use a loop to ensure that we create not one, but three different services. Each one will have the same configuration (standalone-ha.xml) but runs on different ports, using a different set of directories to store its data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run the playbook!
&lt;/h2&gt;

&lt;p&gt;Now, let’s run our Ansible playbook and observe its output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
PLAY [WildFly installation and configuration] **********************************

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

TASK [middleware_automation.wildfly.wildfly_install : Validating arguments against arg spec 'main'] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Ensure prerequirements are fullfilled.] ***
included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_install/tasks/prereqs.yml for localhost

TASK [middleware_automation.wildfly.wildfly_install : Validate credentials] ****
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Validate existing zipfiles wildfly-30.0.1.Final.zip for offline installs] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Validate patch version for offline installs] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Validate existing additional zipfiles {{ eap_archive_filename }} for offline installs] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Check that required packages list has been provided.] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Prepare packages list] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Add JDK package java-11-openjdk-headless.x86_64 to packages list] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Install required packages (5)] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Ensure required local user exists.] ***
included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_install/tasks/user.yml for localhost

TASK [middleware_automation.wildfly.wildfly_install : Check arguments] *********
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Set wildfly group] *******
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Ensure group wildfly exists.] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Ensure user wildfly exists.] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Ensure workdir /opt/ exists.] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Ensure archive_dir /opt/ exists.] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Ensure server is installed] ***
included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_install/tasks/install.yml for localhost

TASK [middleware_automation.wildfly.wildfly_install : Check arguments] *********
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Check local download archive path] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Set download paths] ******
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Check target archive: /opt//wildfly-30.0.1.Final.zip] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Retrieve archive from website: https://github.com/wildfly/wildfly/releases/download] ***
included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_install/tasks/install/web.yml for localhost

TASK [middleware_automation.wildfly.wildfly_install : Check arguments] *********
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Download zipfile from https://github.com/wildfly/wildfly/releases/download/30.0.1.Final/wildfly-30.0.1.Final.zip into /work/wildfly-30.0.1.Final.zip] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Retrieve archive from RHN] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Install server using RPM] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Check downloaded archive] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Copy archive to target nodes] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Check target archive: /opt//wildfly-30.0.1.Final.zip] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Verify target archive state: /opt//wildfly-30.0.1.Final.zip] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Read target directory information: /opt/wildfly-30.0.1.Final] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Extract files from /opt//wildfly-30.0.1.Final.zip into /opt/.] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Note: decompression was not executed] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Read information on server home directory: /opt/wildfly-30.0.1.Final] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Check state of server home directory: /opt/wildfly-30.0.1.Final] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Set instance name] *******
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Deploy custom configuration] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Deploy configuration] ****
changed: [localhost]

TASK [Apply latest cumulative patch] *******************************************
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Ensure required parameters for elytron adapter are provided.] ***
skipping: [localhost]

TASK [Install elytron adapter] *************************************************
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Install server using Prospero] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Check wildfly install directory state] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Validate conditions] *****
ok: [localhost]

TASK [Ensure firewalld configuration allows server port (if enabled).] *********
skipping: [localhost]

TASK [Set up for WildFly instance {{ item }}.] *********************************

TASK [middleware_automation.wildfly.wildfly_systemd : Validating arguments against arg spec 'main'] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] *********
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check current EAP patch installed] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments for yaml configuration] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check if YAML configuration extension is supported in WildFly] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check if YAML configuration extension is supported in EAP] ***
skipping: [localhost]

TASK [Ensure required local user and group exists.] ****************************

TASK [middleware_automation.wildfly.wildfly_install : Check arguments] *********
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Set wildfly group] *******
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Ensure group wildfly exists.] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Ensure user wildfly exists.] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set destination directory for configuration] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set instance destination directory for configuration] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] *********
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set base directory for instance] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] *********
ok: [localhost] =&amp;gt; {
    "changed": false,
    "msg": "All assertions passed"
}

TASK [middleware_automation.wildfly.wildfly_systemd : Set instance name] *******
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set instance name] *******
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set bind address] ********
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Create basedir /opt/wildfly-00 for instance: wildfly-0] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Create deployment directories for instance: wildfly-0] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Deploy custom configuration] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Deploy configuration] ****
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Include YAML configuration extension] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check YAML configuration is disabled] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set systemd envfile destination] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Determine JAVA_HOME for selected JVM] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Determine JAVA_HOME for selected JVM] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set systemd unit file destination] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Deploy service instance configuration: /etc/wildfly-0.conf] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Deploy Systemd configuration for service: /usr/lib/systemd/system/wildfly-0.service] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Perform daemon-reload to ensure the changes are picked up] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Ensure service is started] ***
included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_systemd/tasks/service.yml for localhost

TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] *********
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set instance wildfly-0 state to started] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Validating arguments against arg spec 'main'] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] *********
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check current EAP patch installed] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments for yaml configuration] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check if YAML configuration extension is supported in WildFly] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check if YAML configuration extension is supported in EAP] ***
skipping: [localhost]

TASK [Ensure required local user and group exists.] ****************************

TASK [middleware_automation.wildfly.wildfly_install : Check arguments] *********
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Set wildfly group] *******
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Ensure group wildfly exists.] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Ensure user wildfly exists.] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set destination directory for configuration] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set instance destination directory for configuration] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] *********
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set base directory for instance] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] *********
ok: [localhost] =&amp;gt; {
    "changed": false,
    "msg": "All assertions passed"
}

TASK [middleware_automation.wildfly.wildfly_systemd : Set instance name] *******
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set instance name] *******
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set bind address] ********
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Create basedir /opt/wildfly-11 for instance: wildfly-1] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Create deployment directories for instance: wildfly-1] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Deploy custom configuration] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Deploy configuration] ****
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Include YAML configuration extension] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check YAML configuration is disabled] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set systemd envfile destination] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Determine JAVA_HOME for selected JVM] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Determine JAVA_HOME for selected JVM] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set systemd unit file destination] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Deploy service instance configuration: /etc/wildfly-1.conf] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Deploy Systemd configuration for service: /usr/lib/systemd/system/wildfly-1.service] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Perform daemon-reload to ensure the changes are picked up] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Ensure service is started] ***
included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_systemd/tasks/service.yml for localhost

TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] *********
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set instance wildfly-1 state to started] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Validating arguments against arg spec 'main'] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] *********
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check current EAP patch installed] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments for yaml configuration] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check if YAML configuration extension is supported in WildFly] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check if YAML configuration extension is supported in EAP] ***
skipping: [localhost]

TASK [Ensure required local user and group exists.] ****************************

TASK [middleware_automation.wildfly.wildfly_install : Check arguments] *********
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Set wildfly group] *******
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Ensure group wildfly exists.] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_install : Ensure user wildfly exists.] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set destination directory for configuration] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set instance destination directory for configuration] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] *********
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set base directory for instance] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] *********
ok: [localhost] =&amp;gt; {
    "changed": false,
    "msg": "All assertions passed"
}

TASK [middleware_automation.wildfly.wildfly_systemd : Set instance name] *******
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set instance name] *******
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set bind address] ********
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Create basedir /opt/wildfly-22 for instance: wildfly-2] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Create deployment directories for instance: wildfly-2] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Deploy custom configuration] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Deploy configuration] ****
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Include YAML configuration extension] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Check YAML configuration is disabled] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set systemd envfile destination] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Determine JAVA_HOME for selected JVM] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Determine JAVA_HOME for selected JVM] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set systemd unit file destination] ***
skipping: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Deploy service instance configuration: /etc/wildfly-2.conf] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Deploy Systemd configuration for service: /usr/lib/systemd/system/wildfly-2.service] ***
changed: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Perform daemon-reload to ensure the changes are picked up] ***
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Ensure service is started] ***
included: /root/.ansible/collections/ansible_collections/middleware_automation/wildfly/roles/wildfly_systemd/tasks/service.yml for localhost

TASK [middleware_automation.wildfly.wildfly_systemd : Check arguments] *********
ok: [localhost]

TASK [middleware_automation.wildfly.wildfly_systemd : Set instance wildfly-2 state to started] ***
changed: [localhost]

TASK [Wait for each instance HTTP ports to become available.] ******************
ok: [localhost] =&amp;gt; (item=8080)
ok: [localhost] =&amp;gt; (item=8180)
ok: [localhost] =&amp;gt; (item=8280)

TASK [Checks that WildFly server is running and accessible.] *******************
changed: [localhost] =&amp;gt; (item=8080)
changed: [localhost] =&amp;gt; (item=8180)
changed: [localhost] =&amp;gt; (item=8280)

PLAY RECAP *********************************************************************
localhost                  : ok=105  changed=25   unreachable=0    failed=0    skipped=46   rescued=0    ignored=0   

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the playbook is not that long, but it does a lot for us. It performs almost 100 different tasks! Starting by automatically installing the dependencies, including the JVM required by WildFly, along with downloading its binaries. And the wildfly_systemd role does even more, effortlessly setting up three distinct services, each with its own set of ports and directory layout to store instance-specific data.&lt;/p&gt;

&lt;p&gt;Even better, the WildFly installation is NOT duplicated. All of the binaries live under the /opt/wildfly-27.0.1 directory, but all the data files of each instance are stored in separate folders. This means that we just need to update the binaries, once, and then restart the instances, to deploy a patch or upgrade to a new version of WildFly.&lt;/p&gt;

&lt;p&gt;On top of everything, we configured the instances to use the standalone-ha.xml configuration as the baseline, so they are already set up for clustering.&lt;br&gt;
Check that everything worked as expected&lt;/p&gt;

&lt;p&gt;The easiest way to confirm that the playbook did indeed install WildFly and started three instances of the appserver is to use the systemctl command to check the associate services state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;● wildfly-0.service - JBoss EAP (standalone mode)
   Loaded: loaded (/usr/lib/systemd/system/wildfly-0.service; enabled; vendor preset: disabled)
   Active: active (running) since Wed 2024-01-17 12:06:35 UTC; 2min 11s ago
 Main PID: 747 (standalone.sh)
   CGroup: /system.slice/wildfly-0.service
           ├─747 /bin/sh /opt/wildfly-30.0.1.Final/bin/standalone.sh -c wildfly-0.xml -b 0.0.0.0 -bmanagement 127.0.0.1 -Djboss.bind.address.private=127.0.0.1 -Djboss.default.multicast.address=230.0.0.4 -Djboss.server.config.dir=/opt/wildfly-30.0.1.Final/standalone/configuration/ -Djboss.server.base.dir=/opt/wildfly-00 -Djboss.tx.node.id=wildfly-0 -Djboss.socket.binding.port-offset=0 -Djboss.node.name=wildfly-0 -Dwildfly.statistics-enabled=false
           └─903 /etc/alternatives/jre_11/bin/java -D[Standalone] -Djdk.serialFilter=maxbytes=10485760;maxdepth=128;maxarray=100000;maxrefs=300000 -Xmx1024M -Xms512M --add-exports=java.desktop/sun.awt=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.url.ldap=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.url.ldaps=ALL-UNNAMED --add-exports=jdk.naming.dns/com.sun.jndi.dns=ALL-UNNAMED --add-opens=java.base/com.sun.net.ssl.internal.ssl=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED -Dorg.jboss.boot.log.file=/opt/wildfly-00/log/server.log -Dlogging.configuration=file:/opt/wildfly-30.0.1.Final/standalone/configuration/logging.properties -jar /opt/wildfly-30.0.1.Final/jboss-modules.jar -mp /opt/wildfly-30.0.1.Final/modules org.jboss.as.standalone -Djboss.home.dir=/opt/wildfly-30.0.1.Final -Djboss.server.base.dir=/opt/wildfly-00 -c wildfly-0.xml -b 0.0.0.0 -bmanagement 127.0.0.1 -Djboss.bind.address.private=127.0.0.1 -Djboss.default.multicast.address=230.0.0.4 -Djboss.server.config.dir=/opt/wildfly-30.0.1.Final/standalone/configuration/ -Djboss.server.base.dir=/opt/wildfly-00 -Djboss.tx.node.id=wildfly-0 -Djboss.socket.binding.port-offset=0 -Djboss.node.name=wildfly-0 -Dwildfly.statistics-enabled=false

Jan 17 12:06:38 299529bf09bb standalone.sh[903]: 12:06:38,601 INFO  [org.jboss.modcluster] (ServerService Thread Pool -- 84) MODCLUSTER000032: Listening to proxy advertisements on /224.0.1.105:23364
Jan 17 12:06:38 299529bf09bb standalone.sh[903]: 12:06:38,661 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-3) WFLYUT0006: Undertow HTTPS listener https listening on [0:0:0:0:0:0:0:0]:8443
Jan 17 12:06:38 299529bf09bb standalone.sh[903]: 12:06:38,670 INFO  [org.jboss.as.ejb3] (MSC service thread 1-6) WFLYEJB0493: Jakarta Enterprise Beans subsystem suspension complete
Jan 17 12:06:38 299529bf09bb standalone.sh[903]: 12:06:38,718 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-8) WFLYJCA0001: Bound data source [java:jboss/datasources/ExampleDS]
Jan 17 12:06:38 299529bf09bb standalone.sh[903]: 12:06:38,752 INFO  [org.jboss.as.server.deployment.scanner] (MSC service thread 1-7) WFLYDS0013: Started FileSystemDeploymentService for directory /opt/wildfly-00/deployments
Jan 17 12:06:38 299529bf09bb standalone.sh[903]: 12:06:38,814 INFO  [org.jboss.ws.common.management] (MSC service thread 1-1) JBWS022052: Starting JBossWS 7.0.0.Final (Apache CXF 4.0.0)
Jan 17 12:06:38 299529bf09bb standalone.sh[903]: 12:06:38,924 INFO  [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0212: Resuming server
Jan 17 12:06:38 299529bf09bb standalone.sh[903]: 12:06:38,928 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://127.0.0.1:9990/management
Jan 17 12:06:38 299529bf09bb standalone.sh[903]: 12:06:38,928 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://127.0.0.1:9990
Jan 17 12:06:38 299529bf09bb standalone.sh[903]: 12:06:38,930 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: WildFly Full 30.0.1.Final (WildFly Core 22.0.2.Final) started in 2736ms - Started 311 of 708 services (497 services are lazy, passive or on-demand) - Server configuration file in use: wildfly-0.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploy an application to the Wildlfy cluster
&lt;/h2&gt;

&lt;p&gt;Now, our three WildFly are running, but the cluster has yet to form. Indeed, with no apps there is no reason for the cluster to exist. Let’s modify our Ansible playbook to deploy a simple application to all instances; this will allow us to check that the cluster is working as expected. To achieve this, we’ll leverage another role provided by the WildFly collection: wildfly_utils.&lt;/p&gt;

&lt;p&gt;In our case, we will use the jboss_cli.yml task file, which encapsulates the running of JBoss command-line interface (CLI) queries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;…
  post_tasks:
      - name: "Ensures webapp {{ app.name }} has been retrieved from {{ app.url }}."
        ansible.builtin.get_url:
          url: "{{ app.url }}"
          dest: "{{ wildfly_install_workdir }}/{{ app.name }}"

      - name: "Deploy webapp"
        ansible.builtin.include_role:
          name: wildfly_utils
          tasks_from: jboss_cli.yml
        vars:
          jboss_home: "{{ wildfly_home }}"
          query: "'deploy --force {{ wildfly_install_workdir }}/{{ app.name }}'"
          jboss_cli_controller_port: "{{ item }}"
        loop:
          - 9990
          - 10090
          - 10190
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we will once again execute our playbook so that the web application is deployed on all instances. Once the automation completes successfully, the deployment will trigger the formation of the cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify that the WildFly cluster is running and the app is deployed
&lt;/h2&gt;

&lt;p&gt;You can verify the cluster formation by looking at the log files of any of the three instances:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;…

2022-12-23 15:02:08,252 INFO  [org.infinispan.CLUSTER] (thread-7,ejb,jboss-eap-0) ISPN000094: Received new cluster view for channel ejb: [jboss-eap-0] (3) [jboss-eap-0, jboss-eap-1, jboss-eap-2]
…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using the Ansible collection as an installer for Wildfly
&lt;/h2&gt;

&lt;p&gt;Last remark: while the collection is designed to be used inside a playbook, you can also use the provided playbook to directly install Wildfly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible-playbook -i inventory middleware_automation.wildfly.playbook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Here you go, with a short and simple playbook, we have fully automated the deployment of a WildFly cluster! This playbook can now be used against one, two, three remote machine or even hundreds of them! I hope this will post will have been informative and that it’ll have convinced you to use Ansible to set up your own WildFly servers!&lt;/p&gt;

</description>
      <category>automation</category>
      <category>wildfly</category>
      <category>cluster</category>
      <category>ansible</category>
    </item>
    <item>
      <title>Automate message queue deployment on JBoss EAP</title>
      <dc:creator>Pelisse Romain</dc:creator>
      <pubDate>Thu, 04 Jan 2024 18:00:00 +0000</pubDate>
      <link>https://forem.com/rpelisse/automate-message-queue-deployment-on-jboss-eap-1l01</link>
      <guid>https://forem.com/rpelisse/automate-message-queue-deployment-on-jboss-eap-1l01</guid>
      <description>&lt;p&gt;For decades now, software projects have relied on messaging APIs to exchange data. In the Java/Java EE ecosystem, this method of asynchronous communication has been standardized by the JMS specification. In many cases, individuals and organizations leverage &lt;a href="https://developers.redhat.com/products/eap/overview"&gt;Red Hat JBoss Enterprise Application Platform (JBoss EAP)&lt;/a&gt; to act as message-oriented middleware (MOM), which facilitates the management of message queues and topics.&lt;/p&gt;

&lt;p&gt;Messaging ensures that no messages are lost as they are transmitted from the client and delivered to interested parties. On top of that, JBoss EAP provides authentication and other security-focused capabilities on top of the management functions.&lt;/p&gt;

&lt;p&gt;In this article, we'll show how to fully automate the setup of JBoss EAP and a JMS queue using Ansible so that we can easily make this service available.&lt;/p&gt;

&lt;h1&gt;
  
  
  Prerequisites and installation
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Install Ansible
&lt;/h2&gt;

&lt;p&gt;First, we’ll set up our Ansible control machine, which is where the automation will be executed. On this system, we need to install Ansible as the first step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo dnf install -y ansible-core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the package name has changed recently from &lt;code&gt;ansible&lt;/code&gt; to &lt;code&gt;ansible-core&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Ansible to use Red Hat Automation Hub
&lt;/h2&gt;

&lt;p&gt;An extension to Ansible, an &lt;a href="https://docs.ansible.com/ansible/latest/collections_guide/index.html"&gt;Ansible collection&lt;/a&gt;, dedicated to Red Hat JBoss EAP is available from Automation Hub. Red Hat customers need to add credentials and the location for &lt;a href="https://www.ansible.com/products/automation-hub"&gt;Red Hat Automation Hub&lt;/a&gt; to their Ansible configuration file (&lt;code&gt;ansible.cfg&lt;/code&gt;) to be able to install the content using the ansible-galaxy command-line tool.&lt;/p&gt;

&lt;p&gt;Be sure to replace the with the API token you retrieved from Automation Hub. &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_ansible_automation_platform/1.2/html/getting_started_with_red_hat_ansible_automation_hub/index"&gt;For more information about using Red Hat Automation Hub, please refer to the associated documentation&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#ansible.cfg:
[defaults]
host_key_checking = False
retry_files_enabled = False
nocows = 1

[inventory]
# fail more helpfully when the inventory file does not parse (Ansible 2.4+)
unparsed_is_failed=true

[galaxy]
server_list = automation_hub, galaxy
[galaxy_server.galaxy]
url=https://galaxy.ansible.com/
[galaxy_server.automation_hub]
url=https://cloud.redhat.com/api/automation-hub/
auth_url=https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token
token=&amp;lt;paste-your-token-here&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install the Ansible collection for JBoss EAP
&lt;/h2&gt;

&lt;p&gt;With this configuration, we can now install the Ansible collection for JBoss EAP (&lt;code&gt;redhat.eap&lt;/code&gt;) available on Red Hat Ansible Automation Hub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible-galaxy collection install redhat.eap
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-eap-1.3.4.tar.gz to /root/.ansible/tmp/ansible-local-2529rs7zh7/tmps_4n2eyj/redhat-eap-1.3.4-lr8dvcxo
Installing 'redhat.eap:1.3.4' to '/root/.ansible/collections/ansible_collections/redhat/eap'
Downloading https://console.redhat.com/api/automation-hub/v3/plugin/ansible/content/published/collections/artifacts/redhat-runtimes_common-1.1.0.tar.gz to /root/.ansible/tmp/ansible-local-2529rs7zh7/tmps_4n2eyj/redhat-runtimes_common-1.1.0-o6qfkgju
redhat.eap:1.3.4 was installed successfully
Installing 'redhat.runtimes_common:1.1.0' to '/root/.ansible/collections/ansible_collections/redhat/runtimes_common'
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-2529rs7zh7/tmps_4n2eyj/ansible-posix-1.5.4-4pgukpuo
redhat.runtimes_common:1.1.0 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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we will describe a little later on, this extension for Ansible will manage the entire installation and configuration of the Java application server on the target systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inventory file
&lt;/h2&gt;

&lt;p&gt;Before we can start using our collection, we need to provide the &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_ansible_automation_platform/1.2/html/getting_started_with_red_hat_ansible_automation_hub/index"&gt;inventory of targets to Ansible&lt;/a&gt;. There are several ways to provide this information to the automation tool, but for the purposes of this article, we elected to use a simple ini-formatted inventory file.&lt;/p&gt;

&lt;p&gt;To easily reproduce this article's demonstration, you can use the same control node as the target. This also removes the need to deploy the required SSH key on all the systems involved. To do so, simply use the following inventory file by creating a file called &lt;code&gt;inventory&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[all]
localhost ansible_connection=local

[messaging_servers]
localhost ansible_connection=local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Deploying JBoss EAP
&lt;/h1&gt;

&lt;h2&gt;
  
  
  JBoss EAP installation
&lt;/h2&gt;

&lt;p&gt;Before we configure the JMS queues that will be configured by Ansible, we'll first deploy JBoss EAP. Once the server is successfully running on the target system, we'll adjust the automation to add the required configuration to set up the messaging layer. This is purely for didactic purposes.&lt;/p&gt;

&lt;p&gt;Since we can leverage the content of the &lt;code&gt;redhat.eap&lt;/code&gt; collection, the playbook to install EAP and set it up as systemd service on the target system is minimal. Create a file called &lt;code&gt;eap_jms.yml&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: "Deploy a JBoss EAP"
  hosts: messaging_servers
  vars:
    eap_apply_cp: true
    eap_version: 7.4.0
    eap_offline_install: false
    eap_config_base: 'standalone-full.xml'
  collections:
    - redhat.eap
  roles:
    - eap_install
    - eap_systemd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the Ansible collection for JBoss EAP will also take care of downloading the required assets from the Red Hat Customer Portal (the archive containing the Java app server files). However, one does need to provide the credentials associated with a service account. A Red Hat customer can manage service accounts using the hybrid cloud console. Within this portal, on the &lt;a href="https://console.redhat.com/application-services/service-accounts"&gt;service accounts tab&lt;/a&gt;, you can create a new service account if one does not already exist.&lt;/p&gt;

&lt;p&gt;**Note: **The values obtained from the hybrid cloud console are sensitive and should be managed accordingly. For the purpose of this article, the value is passed to the ansible-playbook command line. Alternatively, &lt;a href="https://docs.ansible.com/ansible/latest/vault_guide/index.html"&gt;ansible-vault&lt;/a&gt; could be used to enforce additional defense mechanisms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible-playbook -i inventory -e rhn_username=&amp;lt;client_id&amp;gt; -e rhn_password=&amp;lt;client_secret&amp;gt; eap_jms.yml

PLAY [Deploy a JBoss EAP] ******************************************************

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

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

TASK [redhat.eap.eap_install : Ensure prerequirements are fullfilled.] *********
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_install/tasks/prereqs.yml for localhost

TASK [redhat.eap.eap_install : Validate credentials] ***************************
ok: [localhost]

TASK [redhat.eap.eap_install : Validate existing zipfiles for offline installs] ***
skipping: [localhost]

TASK [redhat.eap.eap_install : Validate existing zipfiles for offline installs] ***
skipping: [localhost]

TASK [redhat.eap.eap_install : Check that required packages list has been provided.] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Prepare packages list] **************************
skipping: [localhost]

TASK [redhat.eap.eap_install : Add JDK package java-11-openjdk-headless to packages list] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Install required packages (4)] ******************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure required local user exists.] *************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_install/tasks/user.yml for localhost

TASK [redhat.eap.eap_install : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Set eap group] **********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure group eap exists.] ***********************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure user eap exists.] ************************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure workdir /opt/jboss_eap/ exists.] *********
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure archive_dir /opt/jboss_eap/ exists.] *****
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure server is installed] *********************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_install/tasks/install.yml for localhost

TASK [redhat.eap.eap_install : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Check local download archive path] **************
ok: [localhost]

TASK [redhat.eap.eap_install : Set download paths] *****************************
ok: [localhost]

TASK [redhat.eap.eap_install : Check target archive: /opt/jboss_eap//jboss-eap-7.4.0.zip] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Retrieve archive from website: https://github.com/eap/eap/releases/download] ***
skipping: [localhost]

TASK [redhat.eap.eap_install : Retrieve archive from RHN] **********************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_install/tasks/install/rhn.yml for localhost

TASK [redhat.eap.eap_install : Check arguments] ********************************
ok: [localhost]

TASK [Download JBoss EAP from CSP] *********************************************

TASK [redhat.eap.eap_utils : Check arguments] **********************************
ok: [localhost]

TASK [redhat.eap.eap_utils : Retrieve product download using JBoss Network API] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Determine install zipfile from search results] ****
ok: [localhost]

TASK [redhat.eap.eap_utils : Download Red Hat Single Sign-On] ******************
ok: [localhost]

TASK [redhat.eap.eap_install : Install server using RPM] ***********************
skipping: [localhost]

TASK [redhat.eap.eap_install : Check downloaded archive] ***********************
ok: [localhost]

TASK [redhat.eap.eap_install : Copy archive to target nodes] *******************
changed: [localhost]

TASK [redhat.eap.eap_install : Check target archive: /opt/jboss_eap//jboss-eap-7.4.0.zip] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Verify target archive state: /opt/jboss_eap//jboss-eap-7.4.0.zip] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Read target directory information: /opt/jboss_eap/jboss-eap-7.4/] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Extract files from /opt/jboss_eap//jboss-eap-7.4.0.zip into /opt/jboss_eap/.] ***
changed: [localhost]

TASK [redhat.eap.eap_install : Note: decompression was not executed] ***********
skipping: [localhost]

TASK [redhat.eap.eap_install : Read information on server home directory: /opt/jboss_eap/jboss-eap-7.4/] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Check state of server home directory: /opt/jboss_eap/jboss-eap-7.4/] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Set instance name] ******************************
ok: [localhost]

TASK [redhat.eap.eap_install : Deploy custom configuration] ********************
skipping: [localhost]

TASK [redhat.eap.eap_install : Deploy configuration] ***************************
changed: [localhost]

TASK [redhat.eap.eap_install : Ensure required parameters for cumulative patch application are provided.] ***
skipping: [localhost]

TASK [Apply latest cumulative patch] *******************************************
skipping: [localhost]

TASK [redhat.eap.eap_install : Ensure required parameters for elytron adapter are provided.] ***
skipping: [localhost]

TASK [Install elytron adapter] *************************************************
skipping: [localhost]

TASK [redhat.eap.eap_install : Install server using Prospero] ******************
skipping: [localhost]

TASK [redhat.eap.eap_install : Check eap install directory state] **************
ok: [localhost]

TASK [redhat.eap.eap_install : Validate conditions] ****************************
ok: [localhost]

TASK [Ensure firewalld configuration allows server port (if enabled).] *********
skipping: [localhost]

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

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Check current EAP patch installed] **************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check arguments for yaml configuration] *********
skipping: [localhost]

TASK [Ensure required local user and group exists.] ****************************

TASK [redhat.eap.eap_install : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Set eap group] **********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure group eap exists.] ***********************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure user eap exists.] ************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set destination directory for configuration] ****
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set instance destination directory for configuration] ***
ok: [localhost]

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set base directory for instance] ****************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set instance name] ******************************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set instance name] ******************************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set bind address] *******************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Create basedir /opt/jboss_eap/jboss-eap-7.4//standalone for instance: eap] ***
ok: [localhost]

TASK [redhat.eap.eap_systemd : Create deployment directories for instance: eap] ***
ok: [localhost]

TASK [redhat.eap.eap_systemd : Deploy custom configuration] ********************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Deploy configuration] ***************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Include YAML configuration extension] ***********
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check YAML configuration is disabled] ***********
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set systemd envfile destination] ****************
ok: [localhost]

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

TASK [redhat.eap.eap_systemd : Set systemd unit file destination] **************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Deploy service instance configuration: /etc//eap.conf] ***
changed: [localhost]

TASK [redhat.eap.eap_systemd : Deploy Systemd configuration for service: /usr/lib/systemd/system/eap.service] ***
changed: [localhost]

TASK [redhat.eap.eap_systemd : Perform daemon-reload to ensure the changes are picked up] ***
ok: [localhost]

TASK [redhat.eap.eap_systemd : Ensure service is started] **********************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_systemd/tasks/service.yml for localhost

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set instance eap state to started] **************
changed: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=59   changed=6    unreachable=0    failed=0    skipped=22   rescued=0    ignored=0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Validating the installation
&lt;/h2&gt;

&lt;p&gt;Before going any further with our automation, we will be thorough and add a validation step to double-check that the application server is not only running but also functional. This will ensure, down the road, that any JMS-related issue only affects this subsystem.&lt;/p&gt;

&lt;p&gt;The Ansible collection for JBoss EAP comes with a handy role, called &lt;code&gt;eap_validation&lt;/code&gt;, for this purpose, so it's fairly easy to add this step to our playbook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: "Deploy a JBoss EAP"
  hosts: messaging_servers
  vars:
    eap_apply_cp: true
    eap_version: 7.4.0
    eap_offline_install: false
    eap_config_base: 'standalone-full.xml'
  collections:
    - redhat.eap
  roles:
    - eap_install
    - eap_systemd
    - eap_validation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's execute our playbook once again and observe the execution of this validation step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible-playbook -i inventory -e rhn_username=&amp;lt;client_id&amp;gt; -e rhn_password=&amp;lt;client_secret&amp;gt; eap_jms.yml

PLAY [Deploy a JBoss EAP] ******************************************************

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

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

TASK [redhat.eap.eap_install : Ensure prerequirements are fullfilled.] *********
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_install/tasks/prereqs.yml for localhost

TASK [redhat.eap.eap_install : Validate credentials] ***************************
ok: [localhost]

TASK [redhat.eap.eap_install : Validate existing zipfiles for offline installs] ***
skipping: [localhost]

TASK [redhat.eap.eap_install : Validate existing zipfiles for offline installs] ***
skipping: [localhost]

TASK [redhat.eap.eap_install : Check that required packages list has been provided.] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Prepare packages list] **************************
skipping: [localhost]

TASK [redhat.eap.eap_install : Add JDK package java-11-openjdk-headless to packages list] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Install required packages (4)] ******************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure required local user exists.] *************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_install/tasks/user.yml for localhost

TASK [redhat.eap.eap_install : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Set eap group] **********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure group eap exists.] ***********************
changed: [localhost]

TASK [redhat.eap.eap_install : Ensure user eap exists.] ************************
changed: [localhost]

TASK [redhat.eap.eap_install : Ensure workdir /opt/jboss_eap/ exists.] *********
changed: [localhost]

TASK [redhat.eap.eap_install : Ensure archive_dir /opt/jboss_eap/ exists.] *****
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure server is installed] *********************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_install/tasks/install.yml for localhost

TASK [redhat.eap.eap_install : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Check local download archive path] **************
ok: [localhost]

TASK [redhat.eap.eap_install : Set download paths] *****************************
ok: [localhost]

TASK [redhat.eap.eap_install : Check target archive: /opt/jboss_eap//jboss-eap-7.4.0.zip] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Retrieve archive from website: https://github.com/eap/eap/releases/download] ***
skipping: [localhost]

TASK [redhat.eap.eap_install : Retrieve archive from RHN] **********************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_install/tasks/install/rhn.yml for localhost

TASK [redhat.eap.eap_install : Check arguments] ********************************
ok: [localhost]

TASK [Download JBoss EAP from CSP] *********************************************

TASK [redhat.eap.eap_utils : Check arguments] **********************************
ok: [localhost]

TASK [redhat.eap.eap_utils : Retrieve product download using JBoss Network API] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Determine install zipfile from search results] ****
ok: [localhost]

TASK [redhat.eap.eap_utils : Download Red Hat Single Sign-On] ******************
ok: [localhost]

TASK [redhat.eap.eap_install : Install server using RPM] ***********************
skipping: [localhost]

TASK [redhat.eap.eap_install : Check downloaded archive] ***********************
ok: [localhost]

TASK [redhat.eap.eap_install : Copy archive to target nodes] *******************
changed: [localhost]

TASK [redhat.eap.eap_install : Check target archive: /opt/jboss_eap//jboss-eap-7.4.0.zip] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Verify target archive state: /opt/jboss_eap//jboss-eap-7.4.0.zip] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Read target directory information: /opt/jboss_eap/jboss-eap-7.4/] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Extract files from /opt/jboss_eap//jboss-eap-7.4.0.zip into /opt/jboss_eap/.] ***
changed: [localhost]

TASK [redhat.eap.eap_install : Note: decompression was not executed] ***********
skipping: [localhost]

TASK [redhat.eap.eap_install : Read information on server home directory: /opt/jboss_eap/jboss-eap-7.4/] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Check state of server home directory: /opt/jboss_eap/jboss-eap-7.4/] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Set instance name] ******************************
ok: [localhost]

TASK [redhat.eap.eap_install : Deploy custom configuration] ********************
skipping: [localhost]

TASK [redhat.eap.eap_install : Deploy configuration] ***************************
changed: [localhost]

TASK [redhat.eap.eap_install : Ensure required parameters for cumulative patch application are provided.] ***
skipping: [localhost]

TASK [Apply latest cumulative patch] *******************************************
skipping: [localhost]

TASK [redhat.eap.eap_install : Ensure required parameters for elytron adapter are provided.] ***
skipping: [localhost]

TASK [Install elytron adapter] *************************************************
skipping: [localhost]

TASK [redhat.eap.eap_install : Install server using Prospero] ******************
skipping: [localhost]

TASK [redhat.eap.eap_install : Check eap install directory state] **************
ok: [localhost]

TASK [redhat.eap.eap_install : Validate conditions] ****************************
ok: [localhost]

TASK [Ensure firewalld configuration allows server port (if enabled).] *********
skipping: [localhost]

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

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Check current EAP patch installed] **************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check arguments for yaml configuration] *********
skipping: [localhost]

TASK [Ensure required local user and group exists.] ****************************

TASK [redhat.eap.eap_install : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Set eap group] **********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure group eap exists.] ***********************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure user eap exists.] ************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set destination directory for configuration] ****
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set instance destination directory for configuration] ***
ok: [localhost]

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set base directory for instance] ****************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set instance name] ******************************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set instance name] ******************************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set bind address] *******************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Create basedir /opt/jboss_eap/jboss-eap-7.4//standalone for instance: eap] ***
ok: [localhost]

TASK [redhat.eap.eap_systemd : Create deployment directories for instance: eap] ***
ok: [localhost]

TASK [redhat.eap.eap_systemd : Deploy custom configuration] ********************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Deploy configuration] ***************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Include YAML configuration extension] ***********
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check YAML configuration is disabled] ***********
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set systemd envfile destination] ****************
ok: [localhost]

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

TASK [redhat.eap.eap_systemd : Set systemd unit file destination] **************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Deploy service instance configuration: /etc//eap.conf] ***
changed: [localhost]

TASK [redhat.eap.eap_systemd : Deploy Systemd configuration for service: /usr/lib/systemd/system/eap.service] ***
changed: [localhost]

TASK [redhat.eap.eap_systemd : Perform daemon-reload to ensure the changes are picked up] ***
ok: [localhost]

TASK [redhat.eap.eap_systemd : Ensure service is started] **********************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_systemd/tasks/service.yml for localhost

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set instance eap state to started] **************
changed: [localhost]

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

TASK [redhat.eap.eap_validation : Ensure required parameters are provided.] ****
ok: [localhost]

TASK [redhat.eap.eap_validation : Ensure user eap were created.] ***************
ok: [localhost]

TASK [redhat.eap.eap_validation : Validate state of user: eap] *****************
ok: [localhost]

TASK [redhat.eap.eap_validation : Ensure user eap were created.] ***************
ok: [localhost]

TASK [redhat.eap.eap_validation : Validate state of group: eap.] ***************
ok: [localhost]

TASK [redhat.eap.eap_validation : Wait for HTTP port 8080 to become available.] ***
ok: [localhost]

TASK [redhat.eap.eap_validation : Check if web connector is accessible] ********
ok: [localhost]

TASK [redhat.eap.eap_validation : Populate service facts] **********************
ok: [localhost]

TASK [redhat.eap.eap_validation : Check if service is running] *****************
ok: [localhost] =&amp;gt; {
    "changed": false,
    "msg": "All assertions passed"
}

TASK [redhat.eap.eap_validation : Verify server's internal configuration] ******
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_validation/tasks/verify_with_cli_queries.yml for localhost =&amp;gt; (item={'query': '/core-service=server-environment:read-attribute(name=start-gracefully)'})
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_validation/tasks/verify_with_cli_queries.yml for localhost =&amp;gt; (item={'query': '/subsystem=undertow/server=default-server/http-listener=default:read-attribute(name=enabled)'})

TASK [redhat.eap.eap_validation : Ensure required parameters are provided.] ****
ok: [localhost]

TASK [Use CLI query to validate service state: /core-service=server-environment:read-attribute(name=start-gracefully)] ***

TASK [redhat.eap.eap_utils : Ensure required params for JBoss CLI have been provided] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Ensure server's management interface is reachable] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Execute CLI query '/core-service=server-environment:read-attribute(name=start-gracefully)'] ***
ok: [localhost]

TASK [redhat.eap.eap_validation : Validate CLI query was successful] ***********
ok: [localhost]

TASK [redhat.eap.eap_validation : Transform output to JSON] ********************
ok: [localhost]

TASK [redhat.eap.eap_validation : Display transformed result] ******************
skipping: [localhost]

TASK [redhat.eap.eap_validation : Check that query was successfully performed.] ***
ok: [localhost]

TASK [redhat.eap.eap_validation : Ensure required parameters are provided.] ****
ok: [localhost]

TASK [Use CLI query to validate service state: /subsystem=undertow/server=default-server/http-listener=default:read-attribute(name=enabled)] ***

TASK [redhat.eap.eap_utils : Ensure required params for JBoss CLI have been provided] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Ensure server's management interface is reachable] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Execute CLI query '/subsystem=undertow/server=default-server/http-listener=default:read-attribute(name=enabled)'] ***
ok: [localhost]

TASK [redhat.eap.eap_validation : Validate CLI query was successful] ***********
ok: [localhost]

TASK [redhat.eap.eap_validation : Transform output to JSON] ********************
ok: [localhost]

TASK [redhat.eap.eap_validation : Display transformed result] ******************
skipping: [localhost]

TASK [redhat.eap.eap_validation : Check that query was successfully performed.] ***
ok: [localhost]

TASK [redhat.eap.eap_validation : Ensure yaml setup] ***************************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_validation/tasks/yaml_setup.yml for localhost

TASK [Check standard-sockets configuration settings] ***************************

TASK [redhat.eap.eap_utils : Ensure required params for JBoss CLI have been provided] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Ensure server's management interface is reachable] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Execute CLI query /socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=mail-smtp:read-attribute(name=host)] ***
ok: [localhost]

TASK [redhat.eap.eap_validation : Display result of standard-sockets configuration settings] ***
ok: [localhost]

TASK [Check ejb configuration settings] ****************************************

TASK [redhat.eap.eap_utils : Ensure required params for JBoss CLI have been provided] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Ensure server's management interface is reachable] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Execute CLI query /subsystem=ejb3:read-attribute(name=default-resource-adapter-name)] ***
ok: [localhost]

TASK [redhat.eap.eap_validation : Display result of ejb configuration settings] ***
ok: [localhost]

TASK [Check ee configuration settings] *****************************************

TASK [redhat.eap.eap_utils : Ensure required params for JBoss CLI have been provided] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Ensure server's management interface is reachable] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Execute CLI query /subsystem=ee/service=default-bindings:read-attribute(name=jms-connection-factory)] ***
ok: [localhost]

TASK [redhat.eap.eap_validation : Display result of ee configuration settings] ***
ok: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=98   changed=9    unreachable=0    failed=0    skipped=24   rescued=0    ignored=0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the execution of the playbook completed without error, validation of the application server passed successfully.&lt;/p&gt;

&lt;h1&gt;
  
  
  Deploying JMS queues on JBoss EAP using Ansible
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Changing EAP configuration
&lt;/h2&gt;

&lt;p&gt;Because the JMS subsystem is not used in the default JBoss EAP server configuration (&lt;code&gt;standalone.xml&lt;/code&gt;), we also need to use a different profile (&lt;code&gt;standalone-alone.xml&lt;/code&gt;). This is why, in the playbook above, we are specifying the required configuration profile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: "Deploy a JBoss EAP"
  hosts: messaging_servers
  vars:
      eap_apply_cp: true
      eap_version: 7.4.0
      eap_offline_install: false
      eap_config_base: 'standalone-full.xml'
  collections:
    - redhat.eap
  roles:
    - eap_install
    - eap_systemd
    - eap_validation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Leveraging the YAML config feature of EAP using Ansible
&lt;/h1&gt;

&lt;p&gt;In the previous section, JBoss EAP was installed and configured as a systemd service on the target systems. Now, we will update this automation to change the configuration of the app server to ensure a JMS queue is deployed and made available.&lt;/p&gt;

&lt;p&gt;In order to accomplish this goal, we just need to provide a YAML definition with the appropriate configuration for the JMS subsystem of JBoss EAP. This configuration file is used by the app server, on boot, to update its configuration.&lt;/p&gt;

&lt;p&gt;To achieve this, we need to add another file to our project that we named &lt;code&gt;jms_configuration.yml.j2&lt;/code&gt;. While the content of the file itself is YAML, the extension is &lt;code&gt;.j2&lt;/code&gt; because it's a jinja2 template, which allows us to take advantage of the advanced, dynamic capabilities provided by Ansible.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jms_configuration.yml.j2:
wildfly-configuration:
  subsystem:
    messaging-activemq:
      server:
        default:
          jms-queue:
            {{ queue.name }}:
              entries:
                - '{{ queue.entry }}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below, you'll see the playbook updated with all the required parameters to deploy the JMQ queue on JBoss EAP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: "Deploy a Red Hat JBoss EAP server and set up a JMS Queue"
  hosts: messaging_servers
  vars:
    eap_apply_cp: true
    eap_version: 7.4.0
    eap_offline_install: false
    eap_config_base: 'standalone-full.xml'
    eap_enable_yml_config: True
    queue:
      name: MyQueue
      entry: 'java:/jms/queue/MyQueue'
    eap_yml_configs:
      - jms_configuration.yml.j2
  collections:
    - redhat.eap
  roles:
    - eap_install
    - eap_systemd
    - eap_validation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's execute this playbook again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible-playbook -i inventory -e rhn_username=&amp;lt;client_id&amp;gt; -e rhn_password=&amp;lt;client_secret&amp;gt; eap_jms.yml

PLAY [Deploy a Red Hat JBoss EAP server and set up a JMS Queue] ****************

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

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

TASK [redhat.eap.eap_install : Ensure prerequirements are fullfilled.] *********
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_install/tasks/prereqs.yml for localhost

TASK [redhat.eap.eap_install : Validate credentials] ***************************
ok: [localhost]

TASK [redhat.eap.eap_install : Validate existing zipfiles for offline installs] ***
skipping: [localhost]

TASK [redhat.eap.eap_install : Validate existing zipfiles for offline installs] ***
skipping: [localhost]

TASK [redhat.eap.eap_install : Check that required packages list has been provided.] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Prepare packages list] **************************
skipping: [localhost]

TASK [redhat.eap.eap_install : Add JDK package java-11-openjdk-headless to packages list] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Install required packages (4)] ******************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure required local user exists.] *************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_install/tasks/user.yml for localhost

TASK [redhat.eap.eap_install : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Set eap group] **********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure group eap exists.] ***********************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure user eap exists.] ************************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure workdir /opt/jboss_eap/ exists.] *********
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure archive_dir /opt/jboss_eap/ exists.] *****
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure server is installed] *********************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_install/tasks/install.yml for localhost

TASK [redhat.eap.eap_install : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Check local download archive path] **************
ok: [localhost]

TASK [redhat.eap.eap_install : Set download paths] *****************************
ok: [localhost]

TASK [redhat.eap.eap_install : Check target archive: /opt/jboss_eap//jboss-eap-7.4.0.zip] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Retrieve archive from website: https://github.com/eap/eap/releases/download] ***
skipping: [localhost]

TASK [redhat.eap.eap_install : Retrieve archive from RHN] **********************
skipping: [localhost]

TASK [redhat.eap.eap_install : Install server using RPM] ***********************
skipping: [localhost]

TASK [redhat.eap.eap_install : Check downloaded archive] ***********************
ok: [localhost]

TASK [redhat.eap.eap_install : Copy archive to target nodes] *******************
skipping: [localhost]

TASK [redhat.eap.eap_install : Check target archive: /opt/jboss_eap//jboss-eap-7.4.0.zip] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Verify target archive state: /opt/jboss_eap//jboss-eap-7.4.0.zip] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Read target directory information: /opt/jboss_eap/jboss-eap-7.4/] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Extract files from /opt/jboss_eap//jboss-eap-7.4.0.zip into /opt/jboss_eap/.] ***
skipping: [localhost]

TASK [redhat.eap.eap_install : Note: decompression was not executed] ***********
ok: [localhost] =&amp;gt; {
    "msg": "/opt/jboss_eap/jboss-eap-7.4/ already exists and version unchanged, skipping decompression"
}

TASK [redhat.eap.eap_install : Read information on server home directory: /opt/jboss_eap/jboss-eap-7.4/] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Check state of server home directory: /opt/jboss_eap/jboss-eap-7.4/] ***
ok: [localhost]

TASK [redhat.eap.eap_install : Set instance name] ******************************
ok: [localhost]

TASK [redhat.eap.eap_install : Deploy custom configuration] ********************
skipping: [localhost]

TASK [redhat.eap.eap_install : Deploy configuration] ***************************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure required parameters for cumulative patch application are provided.] ***
ok: [localhost] =&amp;gt; {
    "changed": false,
    "msg": "All assertions passed"
}

TASK [Apply latest cumulative patch] *******************************************

TASK [redhat.eap.eap_utils : Check installation] *******************************
ok: [localhost]

TASK [redhat.eap.eap_utils : Set patch directory] ******************************
ok: [localhost]

TASK [redhat.eap.eap_utils : Set download patch archive path] ******************
ok: [localhost]

TASK [redhat.eap.eap_utils : Set patch destination directory] ******************
ok: [localhost]

TASK [redhat.eap.eap_utils : Check download patch archive path] ****************
ok: [localhost]

TASK [redhat.eap.eap_utils : Check local download archive path] ****************
ok: [localhost]

TASK [redhat.eap.eap_utils : Check local downloaded archive: jboss-eap-7.4.9-patch.zip] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Retrieve product download using JBossNetwork API] ***
skipping: [localhost]

TASK [redhat.eap.eap_utils : Determine patch versions list] ********************
skipping: [localhost]

TASK [redhat.eap.eap_utils : Determine latest version] *************************
skipping: [localhost]

TASK [redhat.eap.eap_utils : Determine install zipfile from search results] ****
skipping: [localhost]

TASK [redhat.eap.eap_utils : Determine selected patch from supplied version: 7.4.9] ***
skipping: [localhost]

TASK [redhat.eap.eap_utils : Check remote downloaded archive: /opt/jboss-eap-7.4.9-patch.zip] ***
skipping: [localhost]

TASK [redhat.eap.eap_utils : Download Red Hat EAP patch] ***********************
skipping: [localhost]

TASK [redhat.eap.eap_utils : Set download patch archive path] ******************
ok: [localhost]

TASK [redhat.eap.eap_utils : Check remote download patch archive path] *********
ok: [localhost]

TASK [redhat.eap.eap_utils : Copy patch archive to target nodes] ***************
changed: [localhost]

TASK [redhat.eap.eap_utils : Check patch state] ********************************
ok: [localhost]

TASK [redhat.eap.eap_utils : Set checksum file path for patch] *****************
ok: [localhost]

TASK [redhat.eap.eap_utils : Check /opt/jboss_eap/jboss-eap-7.4//.applied_patch_checksum_f641b6de2807fac18d2a56de7a27c1ea3611e5f3.txt state] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Print when patch has been applied already] ********
skipping: [localhost]

TASK [redhat.eap.eap_utils : Check if management interface is reachable] *******
ok: [localhost]

TASK [redhat.eap.eap_utils : Set apply CP conflict default strategy to default (if not defined): --override-all] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Apply patch /opt/jboss-eap-7.4.9-patch.zip to server installed in /opt/jboss_eap/jboss-eap-7.4/] ***
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_utils/tasks/jboss_cli.yml for localhost

TASK [redhat.eap.eap_utils : Ensure required params for JBoss CLI have been provided] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Ensure server's management interface is reachable] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Execute CLI query 'patch apply --override-all /opt/jboss-eap-7.4.9-patch.zip'] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Display patching result] **************************
ok: [localhost] =&amp;gt; {
    "msg": "Apply patch operation result: {\n    \"outcome\" : \"success\",\n    \"response-headers\" : {\n        \"operation-requires-restart\" : true,\n        \"process-state\" : \"restart-required\"\n    }\n}"
}

TASK [redhat.eap.eap_utils : Set checksum file] ********************************
changed: [localhost]

TASK [redhat.eap.eap_utils : Set latest patch file] ****************************
changed: [localhost]

TASK [redhat.eap.eap_utils : Restart server to ensure patch content is running] ***
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_utils/tasks/jboss_cli.yml for localhost

TASK [redhat.eap.eap_utils : Ensure required params for JBoss CLI have been provided] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Ensure server's management interface is reachable] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Execute CLI query 'shutdown --restart'] ***********
ok: [localhost]

TASK [redhat.eap.eap_utils : Wait for management interface is reachable] *******
ok: [localhost]

TASK [redhat.eap.eap_utils : Stop service if it was started for patching] ******
skipping: [localhost]

TASK [redhat.eap.eap_utils : Display resulting output] *************************
skipping: [localhost]

TASK [redhat.eap.eap_install : Ensure required parameters for elytron adapter are provided.] ***
skipping: [localhost]

TASK [Install elytron adapter] *************************************************
skipping: [localhost]

TASK [redhat.eap.eap_install : Install server using Prospero] ******************
skipping: [localhost]

TASK [redhat.eap.eap_install : Check eap install directory state] **************
ok: [localhost]

TASK [redhat.eap.eap_install : Validate conditions] ****************************
ok: [localhost]

TASK [Ensure firewalld configuration allows server port (if enabled).] *********
skipping: [localhost]

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

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Check current EAP patch installed] **************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Check arguments for yaml configuration] *********
ok: [localhost]

TASK [Ensure required local user and group exists.] ****************************

TASK [redhat.eap.eap_install : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Set eap group] **********************************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure group eap exists.] ***********************
ok: [localhost]

TASK [redhat.eap.eap_install : Ensure user eap exists.] ************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set destination directory for configuration] ****
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set instance destination directory for configuration] ***
ok: [localhost]

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set base directory for instance] ****************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set instance name] ******************************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set instance name] ******************************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set bind address] *******************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Create basedir /opt/jboss_eap/jboss-eap-7.4//standalone for instance: eap] ***
ok: [localhost]

TASK [redhat.eap.eap_systemd : Create deployment directories for instance: eap] ***
ok: [localhost]

TASK [redhat.eap.eap_systemd : Deploy custom configuration] ********************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Deploy configuration] ***************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Include YAML configuration extension] ***********
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_systemd/tasks/yml_config.yml for localhost

TASK [redhat.eap.eap_systemd : Create YAML configuration directory] ************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Enable YAML configuration extension] ************
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Create YAML configuration directory] ************
changed: [localhost]

TASK [redhat.eap.eap_systemd : Enable YAML configuration extension] ************
changed: [localhost]

TASK [redhat.eap.eap_systemd : Deploy YAML configuration files] ****************
changed: [localhost] =&amp;gt; (item=jms_configuration.yml.j2)

TASK [redhat.eap.eap_systemd : Check YAML configuration is disabled] ***********
skipping: [localhost]

TASK [redhat.eap.eap_systemd : Set systemd envfile destination] ****************
ok: [localhost]

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

TASK [redhat.eap.eap_systemd : Set systemd unit file destination] **************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Deploy service instance configuration: /etc//eap.conf] ***
changed: [localhost]

TASK [redhat.eap.eap_systemd : Deploy Systemd configuration for service: /usr/lib/systemd/system/eap.service] ***
ok: [localhost]

TASK [redhat.eap.eap_systemd : Perform daemon-reload to ensure the changes are picked up] ***
ok: [localhost]

TASK [redhat.eap.eap_systemd : Ensure service is started] **********************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_systemd/tasks/service.yml for localhost

TASK [redhat.eap.eap_systemd : Check arguments] ********************************
ok: [localhost]

TASK [redhat.eap.eap_systemd : Set instance eap state to started] **************
ok: [localhost]

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

TASK [redhat.eap.eap_validation : Ensure required parameters are provided.] ****
ok: [localhost]

TASK [redhat.eap.eap_validation : Ensure user eap were created.] ***************
ok: [localhost]

TASK [redhat.eap.eap_validation : Validate state of user: eap] *****************
ok: [localhost]

TASK [redhat.eap.eap_validation : Ensure user eap were created.] ***************
ok: [localhost]

TASK [redhat.eap.eap_validation : Validate state of group: eap.] ***************
ok: [localhost]

TASK [redhat.eap.eap_validation : Wait for HTTP port 8080 to become available.] ***
ok: [localhost]

TASK [redhat.eap.eap_validation : Check if web connector is accessible] ********
ok: [localhost]

TASK [redhat.eap.eap_validation : Populate service facts] **********************
ok: [localhost]

TASK [redhat.eap.eap_validation : Check if service is running] *****************
ok: [localhost] =&amp;gt; {
    "changed": false,
    "msg": "All assertions passed"
}

TASK [redhat.eap.eap_validation : Verify server's internal configuration] ******
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_validation/tasks/verify_with_cli_queries.yml for localhost =&amp;gt; (item={'query': '/core-service=server-environment:read-attribute(name=start-gracefully)'})
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_validation/tasks/verify_with_cli_queries.yml for localhost =&amp;gt; (item={'query': '/subsystem=undertow/server=default-server/http-listener=default:read-attribute(name=enabled)'})

TASK [redhat.eap.eap_validation : Ensure required parameters are provided.] ****
ok: [localhost]

TASK [Use CLI query to validate service state: /core-service=server-environment:read-attribute(name=start-gracefully)] ***

TASK [redhat.eap.eap_utils : Ensure required params for JBoss CLI have been provided] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Ensure server's management interface is reachable] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Execute CLI query '/core-service=server-environment:read-attribute(name=start-gracefully)'] ***
ok: [localhost]

TASK [redhat.eap.eap_validation : Validate CLI query was successful] ***********
ok: [localhost]

TASK [redhat.eap.eap_validation : Transform output to JSON] ********************
ok: [localhost]

TASK [redhat.eap.eap_validation : Display transformed result] ******************
skipping: [localhost]

TASK [redhat.eap.eap_validation : Check that query was successfully performed.] ***
ok: [localhost]

TASK [redhat.eap.eap_validation : Ensure required parameters are provided.] ****
ok: [localhost]

TASK [Use CLI query to validate service state: /subsystem=undertow/server=default-server/http-listener=default:read-attribute(name=enabled)] ***

TASK [redhat.eap.eap_utils : Ensure required params for JBoss CLI have been provided] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Ensure server's management interface is reachable] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Execute CLI query '/subsystem=undertow/server=default-server/http-listener=default:read-attribute(name=enabled)'] ***
ok: [localhost]

TASK [redhat.eap.eap_validation : Validate CLI query was successful] ***********
ok: [localhost]

TASK [redhat.eap.eap_validation : Transform output to JSON] ********************
ok: [localhost]

TASK [redhat.eap.eap_validation : Display transformed result] ******************
skipping: [localhost]

TASK [redhat.eap.eap_validation : Check that query was successfully performed.] ***
ok: [localhost]

TASK [redhat.eap.eap_validation : Ensure yaml setup] ***************************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_validation/tasks/yaml_setup.yml for localhost

TASK [Check standard-sockets configuration settings] ***************************

TASK [redhat.eap.eap_utils : Ensure required params for JBoss CLI have been provided] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Ensure server's management interface is reachable] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Execute CLI query /socket-binding-group=standard-sockets/remote-destination-outbound-socket-binding=mail-smtp:read-attribute(name=host)] ***
ok: [localhost]

TASK [redhat.eap.eap_validation : Display result of standard-sockets configuration settings] ***
ok: [localhost]

TASK [Check ejb configuration settings] ****************************************

TASK [redhat.eap.eap_utils : Ensure required params for JBoss CLI have been provided] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Ensure server's management interface is reachable] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Execute CLI query /subsystem=ejb3:read-attribute(name=default-resource-adapter-name)] ***
ok: [localhost]

TASK [redhat.eap.eap_validation : Display result of ejb configuration settings] ***
ok: [localhost]

TASK [Check ee configuration settings] *****************************************

TASK [redhat.eap.eap_utils : Ensure required params for JBoss CLI have been provided] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Ensure server's management interface is reachable] ***
ok: [localhost]

TASK [redhat.eap.eap_utils : Execute CLI query /subsystem=ee/service=default-bindings:read-attribute(name=jms-connection-factory)] ***
ok: [localhost]

TASK [redhat.eap.eap_validation : Display result of ee configuration settings] ***
ok: [localhost]

RUNNING HANDLER [redhat.eap.eap_systemd : Restart Wildfly] *********************
included: /root/.ansible/collections/ansible_collections/redhat/eap/roles/eap_systemd/tasks/service.yml for localhost

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

RUNNING HANDLER [redhat.eap.eap_systemd : Set instance eap state to restarted] ***
changed: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=127  changed=8    unreachable=0    failed=0    skipped=34   rescued=0    ignored=0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As illustrated in the output above, the YAML definition is now enabled and the configuration of the JBoss EAP running on the target host has been updated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validate the JMS queue deployment
&lt;/h2&gt;

&lt;p&gt;As always, we are going to be thorough and verify that the playbook execution has, indeed, properly set up a JMS queue. To do so, we can simply use the JBoss CLI provided with JBoss EAP to confirm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ /opt/jboss_eap/jboss-eap-7.4/bin/jboss-cli.sh --connect --command="/subsystem=messaging-activemq/server=default/jms-queue=MyQueue:read-resource"
{
    "outcome" =&amp;gt; "success",
    "result" =&amp;gt; {
        "durable" =&amp;gt; true,
        "entries" =&amp;gt; ["queues/MyQueue"],
        "legacy-entries" =&amp;gt; undefined,
        "selector" =&amp;gt; undefined
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output, as shown above, confirms that the server configuration has indeed been updated and that a brand new JMS queue is now available. Since this verification is fairly easy to automate, we will also add it to our playbook.&lt;/p&gt;

&lt;p&gt;The Ansible collection for JBoss EAP comes with a handy wrapper allowing for the execution of the JBoss CLI within a playbook. So, all that is needed is the inclusion of the task and the desired command, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;post_tasks:
    - name: "Check that Queue {{ queue.name }} is available."
      ansible.builtin.include_role:
        name: eap_utils
        tasks_from: jboss_cli.yml
      vars:
        jboss_home: "{{ eap_home }}"
        jboss_cli_query: "/subsystem=messaging-activemq/server=default/jms-queue={{ queue.name }}:read-resource"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Thanks to the Ansible collection for JBoss EAP, we have a minimalistic playbook, spared of all the heavy lifting of managing the Java application server, fulfilling the role of MOM. All the configuration required by the automation concerns only the use case we tried to implement, not the inner working of the solution (JBoss EAP). &lt;/p&gt;

&lt;p&gt;All the configuration required by the automation concerns only the use case we tried to implement, not the inner working of the solution (JBoss EAP). The resulting playbook is safely repeatable and can be used to install the software on any number of target systems. Using the collection for JBoss EAP also makes it easy to keep the deployment up to date.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Migrating to JWS 6 using Ansible</title>
      <dc:creator>Pelisse Romain</dc:creator>
      <pubDate>Wed, 20 Dec 2023 23:00:00 +0000</pubDate>
      <link>https://forem.com/rpelisse/migrating-to-jws-6-using-ansible-1ae9</link>
      <guid>https://forem.com/rpelisse/migrating-to-jws-6-using-ansible-1ae9</guid>
      <description>&lt;p&gt;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.&lt;/p&gt;

&lt;h1&gt;
  
  
  Prerequisites
&lt;/h1&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Once complete, install the redhat.jws collection on the control node using &lt;code&gt;ansible-galaxy&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ 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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the installation of the collection also ensures that the required dependencies are available.&lt;/p&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ cat service_account.yml
    ---
    rhn_username: &amp;lt;service_account_id&amp;gt; 
    rhn_password: &amp;lt;password&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;h1&gt;
  
  
  Installation of JWS 5.7
&lt;/h1&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Using the redhat.jws collection, you can easily install and set up a JWS server using the following playbook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ---
    - 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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The playbook is mostly self-explanatory, however, we'll provide additional commentary on the meaning of a few variables located in the &lt;code&gt;jws5_vars.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    # 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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's run the playbook to install our "legacy" JWS server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ 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] =&amp;gt; {
    "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 =&amp;gt; (item=zip)
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost =&amp;gt; (item=unzip)
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost =&amp;gt; (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] =&amp;gt; (item=openssl)
skipping: [localhost] =&amp;gt; (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] =&amp;gt; {
    "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] =&amp;gt; (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 =&amp;gt; (item=systemd)
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost =&amp;gt; (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] =&amp;gt; (item=conf)
ok: [localhost] =&amp;gt; (item=temp)
ok: [localhost] =&amp;gt; (item=logs)
ok: [localhost] =&amp;gt; (item=webapps)
ok: [localhost] =&amp;gt; (item=bin)

TASK [redhat.jws.jws : Ensure /opt/jws-5.7/tomcat/ files have the recommended priviliges, owner and group] ***
changed: [localhost] =&amp;gt; (item=./conf/catalina.properties)
changed: [localhost] =&amp;gt; (item=./conf/catalina.policy)
changed: [localhost] =&amp;gt; (item=./conf/logging.properties)
changed: [localhost] =&amp;gt; (item=./conf/jaspic-providers.xml)
changed: [localhost] =&amp;gt; (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] =&amp;gt; (item={'template': 'templates/server.xml.j2', 'dest': '/opt/jws-5.7/tomcat/./conf/server.xml'})
changed: [localhost] =&amp;gt; (item={'template': 'templates/web.xml.j2', 'dest': '/opt/jws-5.7/tomcat/./conf/web.xml'})
changed: [localhost] =&amp;gt; (item={'template': 'templates/context.xml.j2', 'dest': '/opt/jws-5.7/tomcat/./conf/context.xml'})
changed: [localhost] =&amp;gt; (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] =&amp;gt; (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 *********************************************************************
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's verify that the server is, indeed, successfully installed and available:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ 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.&amp;gt;
    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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Performing the migration to JWS 6
&lt;/h1&gt;

&lt;p&gt;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 &lt;code&gt;redhat.jws&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;The following playbook could be written to accomplish migrating JWS from version 5 to 6:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ---
    - 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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's run this new playbook:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ ansible-playbook -i inventory jws5-to-6.yml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    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] =&amp;gt; {
        "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 =&amp;gt; (item=zip)
    included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost =&amp;gt; (item=unzip)
    included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost =&amp;gt; (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] =&amp;gt; (item=openssl)
    skipping: [localhost] =&amp;gt; (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] =&amp;gt; {
        "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] =&amp;gt; (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 =&amp;gt; (item=systemd)
    included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost =&amp;gt; (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] =&amp;gt; (item=conf)
    ok: [localhost] =&amp;gt; (item=temp)
    ok: [localhost] =&amp;gt; (item=logs)
    ok: [localhost] =&amp;gt; (item=webapps)
    ok: [localhost] =&amp;gt; (item=bin)

    TASK [redhat.jws.jws : Ensure /opt/jws-6.0/tomcat/ files have the recommended priviliges, owner and group] ***
    changed: [localhost] =&amp;gt; (item=./conf/catalina.properties)
    changed: [localhost] =&amp;gt; (item=./conf/catalina.policy)
    changed: [localhost] =&amp;gt; (item=./conf/logging.properties)
    changed: [localhost] =&amp;gt; (item=./conf/jaspic-providers.xml)
    changed: [localhost] =&amp;gt; (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] =&amp;gt; (item={'template': 'templates/server.xml.j2', 'dest': '/opt/jws-6.0/tomcat/./conf/server.xml'})
    changed: [localhost] =&amp;gt; (item={'template': 'templates/web.xml.j2', 'dest': '/opt/jws-6.0/tomcat/./conf/web.xml'})
    changed: [localhost] =&amp;gt; (item={'template': 'templates/context.xml.j2', 'dest': '/opt/jws-6.0/tomcat/./conf/context.xml'})
    changed: [localhost] =&amp;gt; (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] =&amp;gt; (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   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify that the new &lt;code&gt;jws6&lt;/code&gt; service is indeed up and running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    # 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&amp;gt;
    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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Configuration of the JWS server
&lt;/h1&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    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'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The variables above were provided as a reference to showcase how configurations can be provided. But, for our &lt;code&gt;purposes&lt;/code&gt;, we can omit their use.&lt;/p&gt;

&lt;h1&gt;
  
  
  Handling failure during migration
&lt;/h1&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        - 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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Upgrade strategy
&lt;/h1&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ---
    - name: "Migrate JWS5 to JWS6" hosts: all gather_facts: 
      no serial:
        - 1
        - 30%
        - 60%
      vars_files:
        - vars.yml pre_tasks: …
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;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.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>ansible</category>
      <category>tomcat</category>
      <category>java</category>
    </item>
    <item>
      <title>How Ansible automates JBoss Web Server updates and upgrades</title>
      <dc:creator>Pelisse Romain</dc:creator>
      <pubDate>Thu, 07 Dec 2023 18:00:00 +0000</pubDate>
      <link>https://forem.com/rpelisse/how-ansible-automates-jboss-web-server-updates-and-upgrades-pkj</link>
      <guid>https://forem.com/rpelisse/how-ansible-automates-jboss-web-server-updates-and-upgrades-pkj</guid>
      <description>&lt;p&gt;In the previous article, &lt;a href="https://developers.redhat.com/articles/2021/08/30/automate-red-hat-jboss-web-server-deployments-ansible"&gt;Automate Red Hat JBoss Web Server deployments with Ansible&lt;/a&gt;, I discussed how to fully automate the deployment of Red Hat JBoss Web Server with &lt;a href="https://developers.redhat.com/products/ansible/overview"&gt;Red Hat Ansible Automation Platform&lt;/a&gt;. However, this initial installation and configuration is only the beginning. Once the &lt;a href="https://developers.redhat.com/java"&gt;Java&lt;/a&gt; server is in use, it must be maintained and updated. Otherwise, critical bugs could affect its operation, or a security vulnerability might expose it to bad actors.&lt;/p&gt;

&lt;p&gt;Fortunately, we can utilize Ansible and the &lt;a href="https://console.redhat.com/ansible/automation-hub/repo/published/redhat/jws"&gt;JWS collection&lt;/a&gt; to mitigate these concerns, enabling it to fully patch your deployment by automation and to upgrade the server itself. In this article, we will cover, in detail, how to implement such automation.&lt;/p&gt;

&lt;p&gt;Note: Before you begin the steps in this article, install JBoss Web Server using the Ansible collections described in my &lt;a href="https://developers.redhat.com/articles/2021/08/30/automate-red-hat-jboss-web-server-deployments-ansible"&gt;previous article&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update versus upgrade
&lt;/h2&gt;

&lt;p&gt;First, let's define &lt;em&gt;update&lt;/em&gt; and &lt;em&gt;upgrade&lt;/em&gt;. Updating and upgrading the JBoss Web Server entail very different processes and implementations.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does an update entail?
&lt;/h2&gt;

&lt;p&gt;An update to the JBoss Web Server deploys a set of minor fixes provided by Red Hat via the &lt;a href="https://access.redhat.com/support/policy/updates/jboss_notes"&gt;Red Hat Customer portal&lt;/a&gt;. This update to the Java server code fixes an issue or addresses a security problem (or both). These modifications are packaged into one archive (zip) file in a layout that matches the JBoss Web Server directory structure.&lt;/p&gt;

&lt;p&gt;To deploy this update, you must decompress the archive into the Java server root directory (typically referred to as TOMCAT_HOME). Once the archive decompresses, you must restart the software to ensure the running code uses the changes.&lt;/p&gt;

&lt;p&gt;It is important to note that an update only introduces fixes to the server. There is no functionality (unless required to address the problem) or API changes. Therefore, an update increases only the minor version number, not the major version number of the JBoss Web Server. For instance, a patch to JBoss Web Server 5.6.0 may bring it to version 5.6.4 but not 5.7.0.&lt;/p&gt;

&lt;p&gt;Updates to a more recent minor version rarely require modification to deployed web applications because they only introduce small changes. Updates should be checked regularly and applied as soon as possible to reduce the time a server may be susceptible to a known security issue.&lt;br&gt;
What does an upgrade entail?&lt;/p&gt;

&lt;p&gt;An upgrade is a more involved operation. It comes with API changes and new features. Before an upgrade executes in production, the web applications hosted by JBoss Web Server should be tested with the latest version and may need to be adapted. It is also important to keep in mind that an upgrade to JBoss Web Server represents a change of major version (i.e., shifting from 5.5 to 5.6). We cannot achieve this change by updating the files of the currently installed software. We must perform a completely new installation and migrate the configuration and hosted apps to this new instance.&lt;/p&gt;

&lt;p&gt;In this context, automating the installation of the JBoss Web Server using Ansible brings substantial value. The same combination of tools used for setting up the server can be applied once again to perform an upgrade, ensuring that the software runs in the same configuration as before but with the appropriate upgrades.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; JBoss Web Server is stable software, so changes are unlikely to break backward compatibility even between major versions. That being said, &lt;em&gt;unlikely&lt;/em&gt; is not the same as a guarantee. You may need to apply some changes to the server configuration before upgrading. Before promoting an upgrade to production, you should perform testing in non-production environments.&lt;/p&gt;

&lt;p&gt;Now that you know what performing an update and upgrade to a JBoss Web Server installation entails, you are ready to learn how to employ Ansible for these tasks.&lt;/p&gt;
&lt;h2&gt;
  
  
  Automate the JBoss Web Server update with Ansible
&lt;/h2&gt;

&lt;p&gt;Let's consider the following scenario:&lt;/p&gt;

&lt;p&gt;Red Hat has provided a new update. This update contains a security issue fix and must deploy on all your instances of the JBoss Web Server. Those instances have been set up using the JWS Ansible collection and are running as systemd services. Each provisioned with a few web applications, you can restart it anytime if needed.&lt;/p&gt;

&lt;p&gt;For this article, we will start with the following playbook (quite similar to the one we assembled in the previous article):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: "Red Hat JBoss Web Server installation and configuration"
  hosts: all
  become: true
  vars:
    jws_setup: true
    jboss_web_version: '5.5'
    jws_home: "/opt/jws-{{ jboss_web_version }}/tomcat/"
    jws_install_method: local_zipfiles
    jws_install_dir: /opt
    jws_zipfile: "jws-{{ jboss_web_version }}.0-application-server.zip"
    jws_java_version: 1.8.0
    jws_listen_http_bind_address: 127.0.0.1
    jws_systemd_enabled: True
    jws_service_name: jws
  collections:
    - redhat.jws
  tasks:
    - ansible.builtin.include_role:
        name: jws

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The playbook above employs the redhat.jws collection provided by Red Hat on the &lt;a href="https://console.redhat.com/ansible/ansible-dashboard"&gt;Ansible Automation Hub&lt;/a&gt;. However, you can use the content of this article with the upstream version of &lt;a href="https://console.redhat.com/ansible/automation-hub/repo/published/redhat/jws"&gt;middleware_automation.jws&lt;/a&gt; available on Ansible Galaxy.&lt;/p&gt;

&lt;p&gt;The JWS collection for Ansible offers a nifty role to help apply the update. We need only to supply it with the path to the update's archive, and it will decompress the file and restart JBoss Web Server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
  post_tasks:
    - ansible.builtin.include_role:
        name: jws
        tasks_from: apply_cp.yml
      when:
        - jws_patch_bundle is defined 
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a variable specifying the location of the updated file on the control host to run the playbook and perform the update:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible-playbook -e jws_patch_bundle=jws-5.5.1-application-server.zip -i inventory playbook.yml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can verify that the server has indeed been updated by checking the JBoss Web Server version in the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# cat /opt/jws-5.6/version.txt | grep SP
Red Hat JBoss Web Server - Version 5.5 SP1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Needless to say, when the next update is released, it will require minimal effort. All that's left is updating the path to the updated archive and rerunning the same playbook.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automate the JBoss Web Server upgrade with Ansible
&lt;/h2&gt;

&lt;p&gt;Now that we have fully automated our JBoss Web Server update, let's consider another scenario:&lt;/p&gt;

&lt;p&gt;Our JBoss Web Servers are still running with version 5.4 in production. The application teams have greenlit the upgrade to version 5.5.x with the operations team since it requires no changes within the web applications to accommodate that upgrade. All that remains is completely automating the upgrade process so that Ansible can simultaneously execute the upgrade over all the servers.&lt;/p&gt;

&lt;p&gt;To install the new version, run the previous playbook with the correct JBoss Web Server version.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible-playbook -i inventory -e  jboss_web_version='5.6' playbook.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once Ansible has finished executing, the new JWS server will be up (5.6) with the same configuration as the previous version (5.5), and the server deploys the same web applications.&lt;/p&gt;

&lt;p&gt;This is the beauty of automation. All the heavy lifting was already done when we automated the installation of the JBoss Web Server in our previous article. Now, we can simply reuse this work to easily set up an upgraded server version. The JBoss Web Server configuration upgrade using Ansible is trivial because we fully automated the deployment (despite the upgrade scenario being more complex than the update).&lt;/p&gt;

&lt;h2&gt;
  
  
  The benefits of Ansible and automation
&lt;/h2&gt;

&lt;p&gt;By fully automating the installation of the JBoss Web Server using Ansible, we have made the deployment of new instances easy, repeatable, and efficient. We can now easily maintain those systems, keeping them up to date. We can even perform automated upgrades, ensuring the configuration remains in sync with the previous installation by leveraging even more JWS collection features.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to change an Ansible namespace with FQCN migration tool</title>
      <dc:creator>Pelisse Romain</dc:creator>
      <pubDate>Thu, 23 Nov 2023 17:00:00 +0000</pubDate>
      <link>https://forem.com/rpelisse/how-to-change-an-ansible-namespace-with-fqcn-migration-tool-5f4m</link>
      <guid>https://forem.com/rpelisse/how-to-change-an-ansible-namespace-with-fqcn-migration-tool-5f4m</guid>
      <description>&lt;p&gt;Packaging &lt;a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.html"&gt;Ansible Playbooks&lt;/a&gt; within a collection is the best way to distribute reusable &lt;a href="https://developers.redhat.com/topics/automation"&gt;automation&lt;/a&gt; content. To avoid naming conflicts, developers organize collections inside namespaces. Sometimes situations arise where you need to migrate a collection from one namespace to another, such as a personal or community collection graduating to a more well known or certified namespace.&lt;/p&gt;

&lt;p&gt;Altering the namespace can be a tedious task. However, the Fully Qualified Collection Name (FQCN) migration tool simplifies this process by utilizing the fqcn_migration command. Employing a straightforward configuration file transforms an entire collection from one namespace to another. This article introduces the tool and demonstrates how to use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Case story
&lt;/h2&gt;

&lt;p&gt;Let’s assume we have a collection called useful_stuff living in a community namespace. It has proven valuable to the Ansible community for several years, so there was a decision to move its content from the &lt;code&gt;community&lt;/code&gt; namespace to the &lt;code&gt;ansible&lt;/code&gt; namespace. The migration also presents the opportunity to rename the collection, as its current one was deemed not applicable in the destination namespace.&lt;/p&gt;

&lt;p&gt;The content of useful_stuff adheres to the best practices and conventions associated with Ansible collections, which means that all the roles it contains are prefixed by the collection name (&lt;code&gt;useful_stuff_role_name&lt;/code&gt;) and all variables inside the role are also prefixed with the role name (&lt;code&gt;useful_stuff_varname&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;On top of the runnable Ansible content, the name of the collection and its namespace appears in other files, such as the &lt;code&gt;galaxy.yml&lt;/code&gt; metadata file as well as within the included documentation resource. Also, as a result of the namespace change, a few URLs will need to be updated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using FQCN migration to alter the collection content
&lt;/h2&gt;

&lt;p&gt;To ease the migration from community.useful_stuff to &lt;code&gt;ansible.helpful_things&lt;/code&gt;, we are going to use the FQCN migration tool. First, we’ll need to install it. The tool is packaged as a collection and requires to be available on the system that we will utilize to perform the migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible-galaxy collection install community.fqcn_migration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the collection is installed on the system, use the included playbook from within the collection and set several variables properly. Let’s create a playbook called &lt;code&gt;playbook.yml&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- ansible.builtin.import_playbook: community.fqcn_migration.fqcn_migration
  vars:
    upstream_name: useful_stuff
    downstream_name: helpful_things
    upstream_namespace: 'community'
    downstream_namespace: 'ansible'
    project_git_url: https://github.com/ansible-collections/useful_stuff.git
    project_git_version: main
    galaxy:
      documentation:  https://docs.ansible.com/ansible/latest/collections/ansible/helpfull_things/index.html
      homepage: https://docs.ansible.com/ansible/latest/collections/ansible/helpfull_things/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This playbook can then be run like any other one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible-playbook playbook.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The playbook will first perform a Git clone of the project’s repository of the collection to migrate and alter its content to match the new naming convention required. All that remains is to use git diff to review the modifications, test that the collection still works as expected, and then commit the changes back to the existing repository (or import the resulting content into another repository).&lt;/p&gt;

&lt;p&gt;Note that because fqcn_migration is a development tool, the provided playbook is designed to target the local instance (Ansible controller) rather than on a target (remote) system. As a result, no inventory file is required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating a downstream collection
&lt;/h2&gt;

&lt;p&gt;As demonstrated, &lt;code&gt;fqcn_migration&lt;/code&gt; is already quite helpful for migrating collections from one namespace to another. However, the tool was also developed to support creating downstream collections. Before explaining how to use the tool for such a purpose, let’s briefly clarify what we mean by downstream content. This is a topic that is somewhat specific for providing commercial support over an open source solution.&lt;/p&gt;

&lt;p&gt;Most Red Hat Ansible Automation Platform users are familiar with the Red Hat Enterprise Linux distribution, as a supported and certified version based on the community project Fedora. The same logic applies with JBoss Enterprise Platform being the supported and certified version of the community supported Java/JEE application WildFly. In this context, the community project is often referred to as upstream, while the code base of the Red Hat products is the downstream. Naturally, downstream source derives from the upstream. But, for many reasons, it is frequently transformed (to add files specific content related to the certified product) and then resides in its separate source code repository. Fixes and enhancements in the upstream project are selected afterward and back-ported to the downstream.&lt;/p&gt;

&lt;p&gt;The Ansible Middleware collections are a set of collections designed to help manage Red Hat Runtimes solutions (&lt;a href="https://www.redhat.com/en/technologies/jboss-middleware/application-platform"&gt;RH JBoss EAP&lt;/a&gt;, &lt;a href="https://access.redhat.com/products/red-hat-single-sign-on/"&gt;RH SSO&lt;/a&gt;, &lt;a href="https://www.redhat.com/en/technologies/jboss-middleware/web-server"&gt;RH JBoss Web Server&lt;/a&gt;, &lt;a href="https://www.redhat.com/en/technologies/jboss-middleware/data-grid"&gt;RH Data Gri&lt;/a&gt;d, &lt;a href="https://www.redhat.com/en/technologies/jboss-middleware/amq"&gt;RH AMQ&lt;/a&gt; and &lt;a href="https://www.redhat.com/en/resources/amq-streams-datasheet"&gt;RH AMQ Streams&lt;/a&gt;). Therefore, the upstream collections target the community project (upstream) of each of those projects and each has a downstream version targeting the products provided by Red Hat.&lt;/p&gt;

&lt;p&gt;However, functionally, those collections are the same. The only technical difference is the naming convention and the supportability options. Consequently, to generate the downstream collection of one of those collections, for release purposes, fqcn_migration is also used. Naturally, the transformation performed on the collection is a bit more extensive, as there are extra requirements for documentation along with those that become Ansible certified content published on Ansible automation hub.&lt;/p&gt;

&lt;p&gt;All of these considerations are handled within the fqcn_migration logic so that no manual change is required during a release of the downstream collection. For example, the following is the transformation rule used to convert the &lt;code&gt;middleware_automation.wildfly&lt;/code&gt; collection into the &lt;code&gt;redhat.eap&lt;/code&gt; collection: &lt;a href="https://github.com/ansible-middleware/janus/blob/main/playbooks/eap.yml"&gt;see this configuration file&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This configuration of fqcn_migration is richer than the previous one. We leverage some advanced features that allow us to add or replace content to the collection. Based on a simple placeholder, this capacity allows the user to change the documentation of the downstream collection, so that it matches the documentation requirements of Ansible certified content.&lt;/p&gt;

&lt;p&gt;Once we have generated the downstream collection, we can validate that the result is functional simply by running its transformed molecule test suite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd downstream/eap/
$ molecule test
…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In summary, altering a namespace requires a lot of changes because Ansible collections live inside namespaces, and it is best to use it in variables and role names. However, thanks to the fqcn_migration tool, we can easily migrate a collection’s content from one namespace to another, but also transform its roles and playbooks to generate a fully functional downstream version of the Ansible extension.&lt;/p&gt;

</description>
      <category>ansible</category>
    </item>
    <item>
      <title>Automate JBoss Web Server deployment with the Red Hat Certified Content Collection for JWS</title>
      <dc:creator>Pelisse Romain</dc:creator>
      <pubDate>Wed, 01 Nov 2023 23:00:00 +0000</pubDate>
      <link>https://forem.com/rpelisse/automate-jboss-web-server-deployment-with-the-red-hat-certified-content-collection-for-jws-507l</link>
      <guid>https://forem.com/rpelisse/automate-jboss-web-server-deployment-with-the-red-hat-certified-content-collection-for-jws-507l</guid>
      <description>&lt;p&gt;According to several sources we queried, more than 33 percent of the world's web servers are running Apache Tomcat, while other sources show that it's 48 percent of application servers. Some of these instances have been containerized over the years, but many still run in the traditional setup of a virtual machine with Linux.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.redhat.com/products/webserver/overview"&gt;Red Hat JBoss Web Server (JWS)&lt;/a&gt; combines a web server (Apache HTTPD), a servlet engine (Apache Tomcat), and modules for load balancing (mod_jk and mod_cluster). &lt;a href="https://www.redhat.com/en/technologies/management/ansible"&gt;Ansible&lt;/a&gt; is an automation engine that provides a suite of tools for managing an enterprise at scale. In this article, we'll show how 1+1 becomes 11 by using Ansible to completely automate the deployment of a JBoss Web Server instance on a &lt;a href="https://developers.redhat.com/products/rhel"&gt;Red Hat Enterprise Linux&lt;/a&gt; 8 server.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://developers.redhat.com/articles/2021/08/30/automate-red-hat-jboss-web-server-deployments-ansible"&gt;prior article covered this subject&lt;/a&gt;, but now you can use the Red Hat certified content collection for JBoss Web Server, which has been available since the &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_jboss_web_server/5.7"&gt;5.7 release&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this article, you will automate a JBoss Web Server deployment through the following tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retrieve the archive containing the JBoss Web Server from a repository and install the files on the system.&lt;/li&gt;
&lt;li&gt;Configure the Red Hat Enterprise Linux operating system, creating of users, groups, and the required setup files to enable JBoss Web Server as a systemd service.&lt;/li&gt;
&lt;li&gt;Fine-tune the configuration of the JBoss Web Server server, such as binding it to the appropriate interface and port.&lt;/li&gt;
&lt;li&gt;Deploy a web application and start the systemd service.&lt;/li&gt;
&lt;li&gt;Perform a health check to ensure that the deployed application is accessible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ansible fully automates all those operations, so no manual steps are required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing the target environment
&lt;/h2&gt;

&lt;p&gt;Before you start the automation, you need to specify your target environment. In this case, you'll be using Red Hat Enterprise Linux 8 with Python 3.6. You'll use this setup on both the Ansible control node (where Ansible is executed) and the Ansible target (the system being configured).&lt;/p&gt;

&lt;p&gt;On the control node, confirm the following requirements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cat /etc/redhat-release

Red Hat Enterprise Linux release 8.7 (Ootpa)

$ ansible --version
ansible [core 2.13.3]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.9/site-packages/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.9.13 (main, Nov  9 2022, 13:16:24) [GCC 8.5.0 20210514 (Red Hat 8.5.0-15)]
  jinja version = 3.1.2
  libyaml = True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The procedure in this article might not execute successfully if you use a different Python version or target operating system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing the Red Hat Ansible Certified Content Collection
&lt;/h2&gt;

&lt;p&gt;Once you have Red Hat Enterprise Linux 8 set up and Ansible ready to go, you need to install the &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_jboss_web_server/5.7/html/red_hat_ansible_certified_content_collection_1.2_for_red_hat_jboss_web_server_release_notes/index"&gt;Red Hat Ansible Certified Content Collection 1.2 for Red Hat JBoss Web Server&lt;/a&gt;. Ansible uses the collection to perform the following tasks on JBoss Web Server:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure that the required system dependencies (e.g., unzip) are installed.&lt;/li&gt;
&lt;li&gt;Install Java (if it is missing and requested).&lt;/li&gt;
&lt;li&gt;Install the web server binaries and integrate the software into the system (setting the user, group, etc.).&lt;/li&gt;
&lt;li&gt;Deploy the configuration files.&lt;/li&gt;
&lt;li&gt;Start and enable JBoss Web Server as a &lt;a href="https://www.freedesktop.org/wiki/Software/systemd/"&gt;systemd&lt;/a&gt; service.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To install the &lt;a href="https://console.redhat.com/ansible/automation-hub/repo/published/redhat/jws/"&gt;certified collection for JBoss Web Server&lt;/a&gt;, you'll have to configure Ansible to use Red Hat Automation Hub as a Galaxy server. Follow &lt;a href="https://console.redhat.com/ansible/automation-hub/token"&gt;the instructions on Automation Hub&lt;/a&gt; to retrieve your token and update the &lt;code&gt;ansible.cfg&lt;/code&gt; configuration file in your project directory. Update the &lt;code&gt;&amp;lt;your-token&amp;gt;&lt;/code&gt; field with the token obtained from Automation Hub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[galaxy]
server_list = automation_hub, galaxy

[galaxy_server.galaxy]
url=https://galaxy.ansible.com/

[galaxy_server.automation_hub]
url=https://cloud.redhat.com/api/automation-hub/api/galaxy/
auth_url=https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token

token=&amp;lt;your-token&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the certified collection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 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-302vpskp5wg/tmp2t223yjz/redhat-jws-1.2.4-nrnqzn5k
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-302vpskp5wg/tmp2t223yjz/redhat-runtimes_common-1.1.3-mwgt5h9r
Installing 'redhat.jws:1.2.4' to '/root/.ansible/collections/ansible_collections/redhat/jws'
redhat.jws:1.2.4 was installed successfully
'ansible.posix:1.5.4' is already installed, skipping.
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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://galaxy.ansible.com/"&gt;Ansible Galaxy&lt;/a&gt; fetches and downloads the collection's dependencies. These dependencies include the redhat_csp_download collection, which helps facilitate the retrieval of the archive containing the JBoss Web Server server from either the Red Hat customer portal or a specified local or remote location. For more information about this step, please refer to &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_jboss_web_server/5.7/html-single/installing_jboss_web_server_by_using_the_red_hat_ansible_certified_content_collection/index#install_collection"&gt;the official documentation for Red Hat&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing the Red Hat JBoss Web server
&lt;/h2&gt;

&lt;p&gt;The configuration steps in this section include downloading JBoss Web Server, installing Java, and enabling JBoss Web Server as a system service (&lt;code&gt;systemd&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Downloading the archive
&lt;/h3&gt;

&lt;p&gt;First, you need to download the archive for &lt;a href="https://access.redhat.com/"&gt;JBoss Web Server from the Red Hat Customer Portal&lt;/a&gt;. By default, the collection expects the archive to be in the root folder of the Ansible project. The only remaining requirement is to specify the version of JBoss Web Server being used (5.7) in the playbooks. Based upon this information, the collection determines the path and the full name of the archive.&lt;/p&gt;

&lt;p&gt;Therefore, update the value of &lt;code&gt;jws_version&lt;/code&gt; in the &lt;code&gt;jws-article.yml&lt;/code&gt; playbook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: "Red Hat JBoss Web Server installation and configuration"
  hosts: all
  vars:
    jws_setup: True
    jws_version: 5.7.0
    jws_home: /opt/jws-5.7/tomcat
  …
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Installing Java
&lt;/h3&gt;

&lt;p&gt;JBoss Web Server is a Java-based server, so the target system must have a Java Virtual Machine (JVM) installed. Although Ansible primitives can perform such tasks natively, the redhat.jws collection can also take care of this task, provided that the jws_java_version variable is defined:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jws_home: /opt/jws-5.7/tomcat
jws_java_version: 1.8.0
…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This feature works only if the target system's distribution belongs to the Red Hat &lt;a href="https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_conditionals.html"&gt;family&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enabling JBoss Web Server as a system service (systemd)
&lt;/h3&gt;

&lt;p&gt;The JBoss Web Server server on the target system should run as a service system. The collection can also take care of this task, if the &lt;code&gt;jws_systemd_enabled&lt;/code&gt; variable is defined as &lt;code&gt;True&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jws_java_version: 1.8.0
jws_systemd_enabled: True
jws_service_name: jws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This configuration works only when systemd is installed and the system belongs to the Red Hat family.&lt;/p&gt;

&lt;p&gt;Now that you have defined all the required variables to deploy JBoss Web Server, finish the playbook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
jws_service_name: jws
  collections:
    - redhat.jws
  roles:
    - role: jws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running the playbook
&lt;/h2&gt;

&lt;p&gt;Run the playbook to see whether it works as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible-playbook -i inventory jws_devto_article.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] ***
skipping: [localhost]

TASK [redhat.jws.jws : Check that jws_home has been defined.] ******************
ok: [localhost] =&amp;gt; {
    "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 =&amp;gt; (item=zip)
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost =&amp;gt; (item=unzip)
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost =&amp;gt; (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] =&amp;gt; (item=openssl) 
skipping: [localhost] =&amp;gt; (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] ****************
skipping: [localhost]

TASK [redhat.jws.jws : Create group: tomcat] ***********************************
changed: [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] =&amp;gt; {
    "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] ***************************
ok: [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)] ***
changed: [localhost] =&amp;gt; (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 =&amp;gt; (item=systemd)
included: /root/.ansible/collections/ansible_collections/redhat/jws/roles/jws/tasks/fastpackage.yml for localhost =&amp;gt; (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/jws.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] =&amp;gt; (item=conf)
ok: [localhost] =&amp;gt; (item=temp)
ok: [localhost] =&amp;gt; (item=logs)
ok: [localhost] =&amp;gt; (item=webapps)
ok: [localhost] =&amp;gt; (item=bin)

TASK [redhat.jws.jws : Ensure /opt/jws-5.7/tomcat/ files have the recommended priviliges, owner and group] ***
changed: [localhost] =&amp;gt; (item=./conf/catalina.properties)
changed: [localhost] =&amp;gt; (item=./conf/catalina.policy)
changed: [localhost] =&amp;gt; (item=./conf/logging.properties)
changed: [localhost] =&amp;gt; (item=./conf/jaspic-providers.xml)
changed: [localhost] =&amp;gt; (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] =&amp;gt; (item={'template': 'templates/server.xml.j2', 'dest': '/opt/jws-5.7/tomcat/./conf/server.xml'})
changed: [localhost] =&amp;gt; (item={'template': 'templates/web.xml.j2', 'dest': '/opt/jws-5.7/tomcat/./conf/web.xml'})
changed: [localhost] =&amp;gt; (item={'template': 'templates/context.xml.j2', 'dest': '/opt/jws-5.7/tomcat/./conf/context.xml'})
changed: [localhost] =&amp;gt; (item={'template': 'templates/catalina.properties.j2', 'dest': '/opt/jws-5.7/tomcat/./conf/catalina.properties'})

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

TASK [redhat.jws.jws : Ensure required parameters are provided.] ***************
ok: [localhost]

TASK [redhat.jws.jws : Check if archive contains a selinux policy] *************
ok: [localhost]

TASK [redhat.jws.jws : Install selinux-policy-devel] ***************************
skipping: [localhost]

TASK [redhat.jws.jws : Check if archive contains a selinux policy] *************
skipping: [localhost]

TASK [redhat.jws.jws : Create selinux policy] **********************************
skipping: [localhost]

TASK [redhat.jws.jws : Allow jws.to listen to port] ****************************
skipping: [localhost] =&amp;gt; (item=8080) 
skipping: [localhost] =&amp;gt; (item=8443) 
skipping: [localhost] =&amp;gt; (item=8009) 
skipping: [localhost] =&amp;gt; (item=8005) 
skipping: [localhost]

TASK [redhat.jws.jws : Remove apps] ********************************************
ok: [localhost] =&amp;gt; (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=62   changed=12   unreachable=0    failed=0    skipped=22   rescued=0    ignored=0   


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, quite a lot happened during this execution. Indeed, the redhat.jws role took care of the entire setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploying a base configuration&lt;/li&gt;
&lt;li&gt;Removing unused applications&lt;/li&gt;
&lt;li&gt;Starting the web server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Deploying a web application&lt;/p&gt;

&lt;p&gt;Now that JBoss Web Server is running, modify the playbook to facilitate the deployment of a web application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
roles:
- role: jws
tasks:
  - name: " Checks that server is running"
    ansible.builtin.uri:
      url: "http://localhost:8080/"
      status_code: 404
      return_content: no

  - name: "Deploy demo webapp"
    ansible.builtin.get_url:
      url: 'https://people.redhat.com/~rpelisse/info-1.0.war'
      dest: "{{ jws_home }}/webapps/info.war"
    notify:
      - "Restart Jboss Web Server service"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The configuration uses a &lt;a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_handlers.html"&gt;handler&lt;/a&gt;, provided by the &lt;code&gt;redhat.jws&lt;/code&gt; collection, to ensure that the JBoss Web Server is restarted once the application is downloaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automation saves time and reduces the chance of error
&lt;/h2&gt;

&lt;p&gt;The Red Hat Ansible Certified Content Collection encapsulates, as much as possible, the complexities and the inner workings of Red Hat JBoss Web Server deployment. With the help of the collection, you can focus on your business use case, such as deploying applications, instead of establishing the underlying application server. The result is reduced complexity and faster time to value. The automated process is also repeatable and can be used to set up as many systems as needed.&lt;/p&gt;

</description>
      <category>ansible</category>
      <category>tomcat</category>
      <category>java</category>
      <category>automation</category>
    </item>
    <item>
      <title>Automate your SSO with Ansible and Keycloak</title>
      <dc:creator>Pelisse Romain</dc:creator>
      <pubDate>Thu, 19 Oct 2023 16:00:00 +0000</pubDate>
      <link>https://forem.com/rpelisse/automate-your-sso-with-ansible-and-keycloak-o1k</link>
      <guid>https://forem.com/rpelisse/automate-your-sso-with-ansible-and-keycloak-o1k</guid>
      <description>&lt;p&gt;The article &lt;a href="https://dev.to/rpelisse/deploy-keycloak-single-sign-on-with-ansible-5d1n"&gt;Deploy Keycloak single sign-on with Ansible&lt;/a&gt; discussed how to automate the deployment of Keycloak. In this follow-up article, we’ll use that as a baseline and explore how to automate the configuration of the Keycloak single sign-on (SSO) server, including setting up users, specifying LDAP connection details, and so on.&lt;/p&gt;

&lt;p&gt;Here again, to facilitate our &lt;a href="http://developers.redhat.com/topics/automation"&gt;automation&lt;/a&gt;, we will leverage an &lt;a href="https://developers.redhat.com/products/ansible/overview"&gt;Ansible&lt;/a&gt; collection named &lt;a href="https://galaxy.ansible.com/middleware_automation/keycloak"&gt;middleware_automation.keycloak&lt;/a&gt;, specifically designed for this endeavor. &lt;/p&gt;

&lt;h2&gt;
  
  
  Install Keycloak with Ansible
&lt;/h2&gt;

&lt;p&gt;In the &lt;a href="https://dev.to/rpelisse/deploy-keycloak-single-sign-on-with-ansible-5d1n"&gt;previous article&lt;/a&gt;, we saw in detail how to automate the installation of Keycloak. For this new installment, we’ll start from there using the following playbook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: Playbook for Keycloak Hosts
  hosts: keycloak
  vars:
    keycloak_admin_password: "remembertochangeme"
  collections:
    - middleware_automation.keycloak
  roles:
    - keycloak
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This short playbook will take care of the installation of the single sign-on server itself, which already includes quite a few tasks to perform on the target system, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating appropriate operating system user and group accounts (the name is keycloak for both)&lt;/li&gt;
&lt;li&gt;Downloading the installation archive from the Keycloak website&lt;/li&gt;
&lt;li&gt;Unarchiving the content while ensuring that all the files are associated with the appropriate user and groups along with the correct privileges&lt;/li&gt;
&lt;li&gt;Ensuring that the required version of the &lt;a href="https://developers.redhat.com/java"&gt;Java Virtual Machine (JVM)&lt;/a&gt; is installed&lt;/li&gt;
&lt;li&gt;Integrating the software into the host service management system (in our case, the Linux &lt;a href="https://www.linux.com/training-tutorials/understanding-and-using-systemd/"&gt;systemd&lt;/a&gt; daemon).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, prior to running the playbook, we are going to enhance it even further to perform day two configurations of the Keycloak server, including the configuration of the SSO realm, clients, and users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure single sign-on
&lt;/h2&gt;

&lt;p&gt;The Ansible collection for Keycloak allows defining the realm, client, and users without adding a single, extra task. All that is needed is to define a few extra variables. Of course, those variables are quite structured and need to be formatted correctly for Ansible to be able to configure Keycloak appropriately. The following is a complete, working example of such a configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: Playbook for Keycloak Hosts
  hosts: all
  vars:
    keycloak_admin_password: "remembertochangeme"
    keycloak_realm: TestRealm
  collections:
    - middleware_automation.keycloak
  roles:
    - keycloak
  tasks:
 - name: Keycloak Realm Role
    ansible.builtin.include_role:
        name: keycloak_realm
    vars:
        keycloak_client_default_roles:
        - TestRoleAdmin
        - TestRoleUser
        keycloak_client_users:
        - username: TestUser
            password: password
            client_roles:
            - client: TestClient
                role: TestRoleUser
                realm: "{{ keycloak_realm }}"
        - username: TestAdmin
            password: password
            client_roles:
            - client: TestClient
                role: TestRoleUser
                realm: "{{ keycloak_realm }}"
            - client: TestClient
                role: TestRoleAdmin
                realm: "{{ keycloak_realm }}"
        keycloak_realm: TestRealm
        keycloak_clients:
        - name: TestClient
            roles: "{{ keycloak_client_default_roles }}"
            realm: "{{ keycloak_realm }}"
            public_client: "{{ keycloak_client_public }}"
            web_origins: "{{ keycloak_client_web_origins }}"
            users: "{{ keycloak_client_users }}"
            client_id: TestClient
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that this example, purposely, does not rely on any external sources (such as an LDAP server) so that it can be used easily, to test the collection without requiring the setup of any extra resources.&lt;/p&gt;

&lt;p&gt;Because the SSO configuration is quite dense, we are going to break down each portion to not only provide additional insight, but to illustrate its significance in the SSO configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define the realm
&lt;/h2&gt;

&lt;p&gt;The very first step is to define a realm, which, for the purpose of this article, contains the desired user and role details, but other capabilities provided by Keycloak that will be explored throughout the article. To create the realm, we just need to add one variable to our playbook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;…
            - client: TestClient
             role: TestRoleAdmin
             realm: "{{ keycloak_realm }}"
     keycloak_realm: TestRealm
     keycloak_clients:
…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure roles and users&lt;/p&gt;

&lt;p&gt;The next portion of the variables provided populates the realm with the appropriate details related to users and roles. For the demonstration of this article, we added two users (and two roles) to the realm we are defining:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;TestAdmin&lt;/code&gt;: An admin user who can connect to the SSO server and configure the realm. This user belongs to both roles we defined above.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TestClient&lt;/code&gt;: A user belonging to the realm and thus belongs only in the &lt;code&gt;TestRoleUser&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;…
        keycloak_client_default_roles:
         - TestRoleAdmin
         - TestRoleUser
     keycloak_client_users:
         - username: TestUser
         password: password
         client_roles:
             - client: TestClient
             role: TestRoleUser
             realm: "{{ keycloak_realm }}"
         - username: TestAdmin
         password: password
         client_roles:
             - client: TestClient
             role: TestRoleUser
             realm: "{{ keycloak_realm }}"
             - client: TestClient
             role: TestRoleAdmin
             realm: "{{ keycloak_realm }}"
…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Define Keycloak clients
&lt;/h2&gt;

&lt;p&gt;The last portion of the variables defines the client associated with the roles so that their users can use the SSO service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;…
        keycloak_clients:
        - name: TestClient
            roles: "{{ keycloak_client_default_roles }}"
            realm: "{{ keycloak_realm }}"
            public_client: "{{ keycloak_client_public }}"
            web_origins: "{{ keycloak_client_web_origins }}"
            users: "{{ keycloak_client_users }}"

…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run the playbook
&lt;/h2&gt;

&lt;p&gt;That’s it! With these details provided, we can now run the playbook to deploy Keycloak and fully configure our SSO instance (based on the user's information inside the &lt;code&gt;TestRealm&lt;/code&gt;). Execute the following command to execute the automation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# systemctl status keycloak
● keycloak.service - keycloak Server
   Loaded: loaded (/etc/systemd/system/keycloak.service; enabled; vendor preset: disabled)
   Active: active (running) since Wed 2022-12-28 14:24:28 UTC; 26min ago
  Process: 1607 ExecStop=/opt/keycloak/keycloak-service.sh stop (code=exited, status=0/SUCCESS)
  Process: 1627 ExecStart=/opt/keycloak/keycloak-service.sh start (code=exited, status=0/SUCCESS)
 Main PID: 1742 (java)
   CGroup: /system.slice/keycloak.service
        ├─1630 /bin/sh /opt/keycloak/keycloak-18.0.2/bin/standalone.sh -Djboss.bind.address=0.0.0.0 -Djboss.http.port=8080 -Djboss.https.port=8443 -Djboss.management.http.port=9990 -Djbo&amp;gt;
        └─1742 /usr/lib/jvm/java-11-openjdk-11.0.17.0.8-2.el8_6.x86_64/bin/java -D[Standalone] -server -Xms1024m -Xmx2048m --add-exports=java.desktop/sun.awt=ALL-UNNAMED --add-exports=ja&amp;gt;

Dec 28 14:24:35 515ef9b313a5 keycloak-service.sh[1742]: 14:24:35,360 INFO  [org.jboss.resteasy.resteasy_jaxrs.i18n] (ServerService Thread Pool -- 59) RESTEASY002220: Adding singleton resour&amp;gt;
Dec 28 14:24:35 515ef9b313a5 keycloak-service.sh[1742]: 14:24:35,360 INFO  [org.jboss.resteasy.resteasy_jaxrs.i18n] (ServerService Thread Pool -- 59) RESTEASY002220: Adding singleton resour&amp;gt;
Dec 28 14:24:35 515ef9b313a5 keycloak-service.sh[1742]: 14:24:35,360 INFO  [org.jboss.resteasy.resteasy_jaxrs.i18n] (ServerService Thread Pool -- 59) RESTEASY002220: Adding singleton resour&amp;gt;
Dec 28 14:24:35 515ef9b313a5 keycloak-service.sh[1742]: 14:24:35,360 INFO  [org.jboss.resteasy.resteasy_jaxrs.i18n] (ServerService Thread Pool -- 59) RESTEASY002210: Adding provider singlet&amp;gt;
Dec 28 14:24:35 515ef9b313a5 keycloak-service.sh[1742]: 14:24:35,428 INFO  [org.wildfly.extension.undertow] (ServerService Thread Pool -- 59) WFLYUT0021: Registered web context: '/auth' for&amp;gt;
Dec 28 14:24:35 515ef9b313a5 keycloak-service.sh[1742]: 14:24:35,487 INFO  [org.jboss.as.server] (ServerService Thread Pool -- 42) WFLYSRV0010: Deployed "keycloak-server.war" (runtime-name &amp;gt;
Dec 28 14:24:35 515ef9b313a5 keycloak-service.sh[1742]: 14:24:35,522 INFO  [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0212: Resuming server
Dec 28 14:24:35 515ef9b313a5 keycloak-service.sh[1742]: 14:24:35,524 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: Keycloak 18.0.2 (WildFly Core 18.1.1.Final) started in 8112ms&amp;gt;
Dec 28 14:24:35 515ef9b313a5 keycloak-service.sh[1742]: 14:24:35,526 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://127.0.0.1:9990/&amp;gt;
Dec 28 14:24:35 515ef9b313a5 keycloak-service.sh[1742]: 14:24:35,527 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://127.0.0.1:9990
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To go even further, we can add a check to our playbook that will use the Keycloak admin credentials to get a token from the SSO server. This emulates what will happen when a user tries to access an application using the SSO service. Thus, if it works fine, it confirms the service is functional:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: Verify token api call
  ansible.builtin.uri:
    url: "{{ keycloak_port }}/auth/realms/master/protocol/openid-connect/token"
    method: POST
    body: "client_id=admin-cli&amp;amp;username=admin&amp;amp;password={{ keycloak_admin_password }}&amp;amp;grant_type=password"
    validate_certs: no
    register: keycloak_auth_response
    until: keycloak_auth_response.status == 200
    retries: 2
    delay: 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;On top of deploying the Keycloak server, we have fully automated the configuration of our SSO. We can deploy a fully functional instance, in any environment, without any manual intervention. Most importantly, it is accomplished in a secure and repeatable fashion. With just this playbook, you can set up the entire infrastructure for SSO in a matter of minutes using the tooling provided by the Ansible Middleware project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.freepik.com/free-photo/audio-snake-stage-box-with-xlr-cables-jacks-live-show_13738481.htm#query=signal%20computers&amp;amp;position=21&amp;amp;from_view=search&amp;amp;track=ais"&gt;Cover Image by pvproductions on Freepik&lt;/a&gt;&lt;/p&gt;

</description>
      <category>automation</category>
      <category>ansible</category>
      <category>keycloak</category>
      <category>sso</category>
    </item>
    <item>
      <title>Deploy Keycloak single sign-on with Ansible</title>
      <dc:creator>Pelisse Romain</dc:creator>
      <pubDate>Thu, 05 Oct 2023 16:00:00 +0000</pubDate>
      <link>https://forem.com/rpelisse/deploy-keycloak-single-sign-on-with-ansible-5d1n</link>
      <guid>https://forem.com/rpelisse/deploy-keycloak-single-sign-on-with-ansible-5d1n</guid>
      <description>&lt;p&gt;This article is the fourth installment in our series on &lt;a href="https://developers.redhat.com/products/ansible/overview" rel="noopener noreferrer"&gt;Ansible&lt;/a&gt; for middleware. In this article, you'll use Ansible to simplify and automate the installation of &lt;a href="https://www.redhat.com/en/blog/getting-started-keycloak-single-sign-operator" rel="noopener noreferrer"&gt;Keycloak&lt;/a&gt;, a popular &lt;a href="https://developers.redhat.com/topics/open-source" rel="noopener noreferrer"&gt;open source&lt;/a&gt; tool to implement single sign-on for Web applications. The previous articles in this series are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://developers.redhat.com/articles/2021/08/30/automate-red-hat-jboss-web-server-deployments-ansible" rel="noopener noreferrer"&gt;Automate Red Hat JBoss Web Server deployments with Ansible&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.redhat.com/articles/2022/02/08/automate-and-deploy-jboss-eap-cluster-ansible" rel="noopener noreferrer"&gt;Automate and deploy a JBoss EAP cluster with Ansible&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.redhat.com/articles/2022/03/21/deploy-infinispan-automatically-ansible" rel="noopener noreferrer"&gt;Deploy Infinispan automatically with Ansible&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The tutorial in this article builds on an Ansible Collection named &lt;a href="https://galaxy.ansible.com/middleware_automation/keycloak" rel="noopener noreferrer"&gt;middleware_automation.keycloak&lt;/a&gt;, which has been specifically designed for this endeavor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To make use of this tutorial, you need a &lt;a href="https://developers.redhat.com/products/rhel" rel="noopener noreferrer"&gt;Red Hat Enterprise Linux&lt;/a&gt; or &lt;a href="https://getfedora.org/" rel="noopener noreferrer"&gt;Fedora&lt;/a&gt; system, along with version 2.9 or higher of Ansible (preferably the latest version).&lt;/p&gt;

&lt;h2&gt;
  
  
  Install the collection
&lt;/h2&gt;

&lt;p&gt;The very first step, of course, is to install the collection itself, so that Ansible can use its content inside playbooks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ansible-galaxy collection install middleware_automation.keycloak
Starting galaxy collection install process
Process install dependency map
Starting collection install process
Downloading https://galaxy.ansible.com/download/middleware_automation-keycloak-1.0.0.tar.gz to /root/.ansible/tmp/ansible-local-24nzydu97b/tmpaql0qbek/middleware_automation-keycloak-1.0.0-8yma1_vi
Installing 'middleware_automation.keycloak:1.0.0' to '/root/.ansible/collections/ansible_collections/middleware_automation/keycloak'
Downloading https://galaxy.ansible.com/download/middleware_automation-redhat_csp_download-1.2.1.tar.gz to /root/.ansible/tmp/ansible-local-24nzydu97b/tmpaql0qbek/middleware_automation-redhat_csp_download-1.2.1-4po4eg4w
middleware_automation.keycloak:1.0.0 was installed successfully
Installing 'middleware_automation.redhat_csp_download:1.2.1' to '/root/.ansible/collections/ansible_collections/middleware_automation/redhat_csp_download'
Downloading https://galaxy.ansible.com/download/middleware_automation-wildfly-1.0.1.tar.gz to /root/.ansible/tmp/ansible-local-24nzydu97b/tmpaql0qbek/middleware_automation-wildfly-1.0.1-ayf0n_nq
middleware_automation.redhat_csp_download:1.2.1 was installed successfully
Installing 'middleware_automation.wildfly:1.0.1' to '/root/.ansible/collections/ansible_collections/middleware_automation/wildfly'
middleware_automation.wildfly:1.0.1 was installed successfully
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The collection has the following dependencies:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;middleware_automation.redhat_csp&lt;/code&gt;: This collection allows Ansible to connect to the Red Hat Customer Portal to download &lt;a href="https://access.redhat.com/products/red-hat-single-sign-on" rel="noopener noreferrer"&gt;Red Hat's single sign-on technology&lt;/a&gt;, which is a productized and supported version of Keycloak. We won't use this feature in this article.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;middleware_automation.wildfly&lt;/code&gt;: Keycloak runs on top of the &lt;a href="https://www.wildfly.org/" rel="noopener noreferrer"&gt;Wildfly&lt;/a&gt; application server, including &lt;a href="https://developers.redhat.com/products/eap/overview" rel="noopener noreferrer"&gt;Red Hat JBoss Enterprise Application Platform (JBoss EAP)&lt;/a&gt;, which is the version of Wildfly supported by Red Hat. For more details about this collection, please refer to the second article in this series, &lt;a href="https://developers.redhat.com/articles/2022/02/08/automate-and-deploy-jboss-eap-cluster-ansible" rel="noopener noreferrer"&gt;Automate and deploy a JBoss EAP Cluster with Ansible&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Depending on the configuration of the machine used as the Ansible controller, you might need to add some Python dependencies so that Ansible will have the libraries required to make use of the collection. Install them by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# pip3 install lxml jmespath
Collecting lxml
  Downloading lxml-4.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl (6.9 MB)
     |████████████████████████████████| 6.9 MB 1.9 MB/s
Collecting jmespath
  Downloading jmespath-0.10.0-py2.py3-none-any.whl (24 kB)
Installing collected packages: lxml, jmespath
Successfully installed jmespath-0.10.0 lxml-4.7.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that the collection and its dependencies are installed, you can use it in an automation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: Playbook for keycloak Hosts
  hosts: keycloak
  collections:
    - middleware_automation.keycloak
  tasks:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; In order for this playbook to perform the installation outlined here, Ansible must have sudo or root privileges on the target hosts.&lt;br&gt;
Install Keycloak with Ansible&lt;/p&gt;

&lt;p&gt;Thanks to the dedicated collection you just installed, automating the installation and configuration of Keycloak is easy. However, before you implement this inside your playbook, we should recap what we mean here by installing Keycloak. Indeed, this task encompasses quite a few operations that are performed on the target system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating appropriate operating system user and group accounts (the name is &lt;code&gt;keycloak&lt;/code&gt; for both)&lt;/li&gt;
&lt;li&gt;Downloading the installation archive from the Keycloak website&lt;/li&gt;
&lt;li&gt;Unarchiving the content while ensuring that all the files are associated with the appropriate user and groups along with the correct privileges&lt;/li&gt;
&lt;li&gt;Ensuring that the required version of the Java Virtual Machine (JVM) is installed&lt;/li&gt;
&lt;li&gt;Integrating the software into the host service management system (in our case, the Linux &lt;a href="https://www.linux.com/training-tutorials/understanding-and-using-systemd/" rel="noopener noreferrer"&gt;systemd&lt;/a&gt; daemon).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of this is achieved and is fully automated by the following short playbook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: Playbook for Keycloak Hosts
  hosts: keycloak
  collections:
    - middleware_automation.keycloak
  tasks:
    - name: Include keycloak role
      ansible.builtin.include_role:
        name: middleware_automation.keycloak.keycloak
      vars:
        keycloak_admin_password: "changeme"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The playbook begins by defining a variable for the Keycloak server administrative user. Note that, because this variable is a password, it should really be secured using &lt;a href="https://docs.ansible.com/ansible/latest/vault_guide/index.html" rel="noopener noreferrer"&gt;Ansible Vault&lt;/a&gt; or some other secrets management system. However, that task is beyond the scope of this article.&lt;/p&gt;

&lt;p&gt;The configuration then adds the Ansible collection for Keycloak to the list used by the playbook and adds the associated &lt;code&gt;middleware_automation.keycloak.keycloak&lt;/code&gt; role to the list of roles that the playbook uses.&lt;/p&gt;

&lt;p&gt;Run this playbook as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ansible-playbook -i inventory playbook.yml

PLAY [Playbook for Keycloak Hosts] ***************************************************************************************************************************

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

TASK [middleware_automation.keycloak.keycloak : Validating arguments against arg spec 'main'] ****************************************************************
ok: [localhost]

TASK [middleware_automation.keycloak.keycloak : Check prerequisites] *****************************************************************************************
included: /root/.ansible/collections/ansible_collections/middleware_automation/keycloak/roles/keycloak/tasks/prereqs.yml for localhost

TASK [middleware_automation.keycloak.keycloak : Validate configuration]
…
TASK [middleware_automation.keycloak.keycloak : Create keycloak admin user] **********************************************************************************
changed: [localhost]

TASK [middleware_automation.keycloak.keycloak : Restart keycloak] ********************************************************************************************
included: /root/.ansible/collections/ansible_collections/middleware_automation/keycloak/roles/keycloak/tasks/restart_keycloak.yml for localhost

TASK [middleware_automation.keycloak.keycloak : Restart and enable keycloak service] ************************************************************************
changed: [localhost]

TASK [middleware_automation.keycloak.keycloak : Wait until keycloak becomes active http://localhost:9990/health] *********************************************
FAILED - RETRYING: [localhost]: Wait until keycloak becomes active http://localhost:9990/health (25 retries left).
ok: [localhost]

PLAY RECAP ***************************************************************************************************************************************************
localhost                  : ok=44   changed=2    unreachable=0    failed=0    skipped=14   rescued=1    ignored=0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More than forty tasks from the included role have been executed, taking care of all the requirements mentioned earlier: user and group creation, the software download, installing the required JVM, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check for successful installation
&lt;/h2&gt;

&lt;p&gt;Once the playbook finishes its execution, you can confirm that Keycloak is now running as a service by verifying the status of the service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ● keycloak.service - Keycloak Server
   Loaded: loaded (/etc/systemd/system/keycloak.service; enabled; vendor preset: disabled)
   Active: active (running) since Mon 2022-03-21 08:06:08 UTC; 3min 36s ago
  Process: 1553 ExecStop=/opt/keycloak/keycloak-service.sh stop (code=exited, status=0/SUCCESS)
  Process: 1571 ExecStart=/opt/keycloak/keycloak-service.sh start (code=exited, status=0/SUCCESS)
 Main PID: 1636 (java)
    Tasks: 79 (limit: 1638)
   Memory: 1012.8M
   CGroup: /system.slice/keycloak.service
           ├─1574 /bin/sh /opt/keycloak/keycloak-15.0.2/bin/standalone.sh -Djboss.bind.address=0.0.0.0 -Djboss.http.port=8080 -Djboss.https.port=8443 -Djboss.management.http.port=9990 -Djboss.management.https.port=9993 -Djboss.node.name=&amp;gt;
           └─1636 java -D[Standalone] -server -Xms1024m -Xmx2048m -Dorg.jboss.boot.log.file=/opt/keycloak/keycloak-15.0.2/standalone/log/server.log -Dlogging.configuration=file:/opt/keycloak/keycloak-15.0.2/standalone/configuration/loggi&amp;gt;

Mar 21 08:06:17 7efa2c53bfe8 keycloak-service.sh[1571]: 08:06:17,566 INFO  [org.jboss.resteasy.resteasy_jaxrs.i18n] (ServerService Thread Pool -- 65) RESTEASY002220: Adding singleton resource org.keycloak.services.resources.RobotsResourc&amp;gt;
Mar 21 08:06:17 7efa2c53bfe8 keycloak-service.sh[1571]: 08:06:17,567 INFO  [org.jboss.resteasy.resteasy_jaxrs.i18n] (ServerService Thread Pool -- 65) RESTEASY002210: Adding provider singleton org.keycloak.services.util.ObjectMapperResolv&amp;gt;
Mar 21 08:06:17 7efa2c53bfe8 keycloak-service.sh[1571]: 08:06:17,567 INFO  [org.jboss.resteasy.resteasy_jaxrs.i18n] (ServerService Thread Pool -- 65) RESTEASY002220: Adding singleton resource org.keycloak.services.resources.WelcomeResour&amp;gt;
Mar 21 08:06:17 7efa2c53bfe8 keycloak-service.sh[1571]: 08:06:17,567 INFO  [org.jboss.resteasy.resteasy_jaxrs.i18n] (ServerService Thread Pool -- 65) RESTEASY002220: Adding singleton resource org.keycloak.services.resources.RealmsResourc&amp;gt;
Mar 21 08:06:17 7efa2c53bfe8 keycloak-service.sh[1571]: 08:06:17,650 INFO  [org.wildfly.extension.undertow] (ServerService Thread Pool -- 65) WFLYUT0021: Registered web context: '/auth' for server 'default-server'
Mar 21 08:06:17 7efa2c53bfe8 keycloak-service.sh[1571]: 08:06:17,728 INFO  [org.jboss.as.server] (ServerService Thread Pool -- 43) WFLYSRV0010: Deployed "keycloak-server.war" (runtime-name : "keycloak-server.war")
Mar 21 08:06:17 7efa2c53bfe8 keycloak-service.sh[1571]: 08:06:17,764 INFO  [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0212: Resuming server
Mar 21 08:06:17 7efa2c53bfe8 keycloak-service.sh[1571]: 08:06:17,766 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: Keycloak 15.0.2 (WildFly Core 15.0.1.Final) started in 9864ms - Started 596 of 873 services (584 services are&amp;gt;
Mar 21 08:06:17 7efa2c53bfe8 keycloak-service.sh[1571]: 08:06:17,768 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://127.0.0.1:9990/management
Mar 21 08:06:17 7efa2c53bfe8 keycloak-service.sh[1571]: 08:06:17,768 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://127.0.0.1:9990/code&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the playbook execution itself verifies that the service is running and that the Keycloak server itself is also available:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;… 
TASK [middleware_automation.keycloak.keycloak : Restart and enable keycloak service] **************************************************
changed: [localhost]

TASK [middleware_automation.keycloak.keycloak : Wait until keycloak becomes active http://localhost:9990/health] ***********************
ok: [localhost]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, for the sake of being thorough, you should double-check that the Keycloak port is indeed accessible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# curl -I http://localhost:9990/health
HTTP/1.1 200 OK
Connection: keep-alive
Content-Type: application/json
Content-Length: 283
Date: Fri, 18 Mar 2022 09:38:00 GMT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you navigate to &lt;a href="http://localhost:8080/" rel="noopener noreferrer"&gt;http://localhost:8080/&lt;/a&gt;, you will have access to your fully ready installation of Keycloak (Figure 1).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo5869n6kk9r91thvj7as.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo5869n6kk9r91thvj7as.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
Figure 1: The Keycloak administrative site should be running on your local computer.&lt;/p&gt;

&lt;p&gt;To summarize, at the end of this playbook execution, you'll have a running &lt;code&gt;systemd&lt;/code&gt; service managing an instance of Keycloak.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By using Ansible and the Ansible Collection for Keycloak as outlined in this article, you can fully automate the deployment of a single sign-on server. In this article, Ansible has performed all the heavy lifting: downloading software, preparing the operating system (user, group, firewall), deploying the binary files and the configuration, setting up the service (&lt;code&gt;systemd&lt;/code&gt;), and even preparing the required administrative account. The Ansible Collection for Keycloak allows you to streamline the installation and configuration of Keycloak, thus enabling you to scale deployments as necessary and ensure repeatability across them all.&lt;/p&gt;

&lt;p&gt;In an upcoming article, we'll discuss how to further automate Keycloak's single sign-on service by creating realms and their members using Ansible.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Update and upgrade JBoss EAP with Ansible</title>
      <dc:creator>Pelisse Romain</dc:creator>
      <pubDate>Thu, 21 Sep 2023 15:00:00 +0000</pubDate>
      <link>https://forem.com/rpelisse/update-and-upgrade-jboss-eap-with-ansible-3c2c</link>
      <guid>https://forem.com/rpelisse/update-and-upgrade-jboss-eap-with-ansible-3c2c</guid>
      <description>&lt;p&gt;In this follow-up to &lt;a href="https://developers.redhat.com/articles/2022/02/08/automate-and-deploy-jboss-eap-cluster-ansible"&gt;Automate and deploy a JBoss EAP cluster with Ansible&lt;/a&gt;, we will explain how to maintain and keep those instances updated, again in a fully &lt;a href="https://developers.redhat.com/topics/automation"&gt;automated&lt;/a&gt; manner, leveraging &lt;a href="https://console.redhat.com/ansible/automation-hub/repo/published/redhat/eap/"&gt;Ansible and the Ansible collection for Red Hat JBoss Enterprise Application Platform (EAP)&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Indeed, it is critical to ensure that all JEE application server instances always be up to date, especially in regard to security fixes. Therefore, we’ll discuss not only how to apply patches to update the server but also how to perform an upgrade to migrate to a new major version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;In the &lt;a href="https://developers.redhat.com/articles/2022/02/08/automate-and-deploy-jboss-eap-cluster-ansible"&gt;previous article&lt;/a&gt;, we used the following playbook to install the WildFly cluster using Ansible on one single host. However, in this article, we’ll use only one instance of JBoss EAP (and no longer WildFly) for simplicity's sake.&lt;/p&gt;

&lt;p&gt;You can use the following playbook to install an instance of JBoss EAP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: Install EAP 7
  hosts: all
  collections:
    - redhat.eap
  roles:
    - eap_install
    - eap_systemd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The playbook above uses the &lt;code&gt;redhat.eap&lt;/code&gt; certified collection instead of the upstream &lt;code&gt;middleware_automation.wildfly&lt;/code&gt; instance. The previous article used WildFly (the community version of the JEE application server) instead of JBoss EAP (the product supported by Red Hat). However, as updates are rarely produced for the upstream version (because of the fast release cycle, it’s easier to update to the next version), this article will focus on JBoss EAP, as product users often have to manage such updates.&lt;br&gt;
For the playbook above to function as expected, you will need to install the collections &lt;code&gt;redhat.eap&lt;/code&gt; on the Ansible controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ansible-galaxy collection install redhat.eap
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-eap-1.3.1.tar.gz to /root/.ansible/tmp/ansible-local-344ezcdnc0/tmpc0c7yq1u/redhat-eap-1.3.1-b5h7g9vf
Downloading https://console.redhat.com/api/automation-hub/v3/plugin/ansible/content/published/collections/artifacts/redhat-redhat_csp_download-1.2.2.tar.gz to /root/.ansible/tmp/ansible-local-344ezcdnc0/tmpc0c7yq1u/redhat-redhat_csp_download-1.2.2-2kmr5p0m
Installing 'redhat.eap:1.3.1' to '/root/.ansible/collections/ansible_collections/redhat/eap'
redhat.eap:1.3.1 was installed successfully
Installing 'redhat.redhat_csp_download:1.2.2' to '/root/.ansible/collections/ansible_collections/redhat/redhat_csp_download'
redhat.redhat_csp_download:1.2.2 was installed successfully
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As &lt;code&gt;redhat.eap&lt;/code&gt; is a certified collection only available to Red Hat customers, you need to configure the ansible.cfg file to use Ansible Automation Hub so that the collection can be retrieved:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# cat ansible.cfg
[defaults]
host_key_checking = False
retry_files_enabled = False
nocows = 1

[inventory]
# fail more helpfully when the inventory file does not parse (Ansible 2.4+)
unparsed_is_failed=true

[galaxy]
server_list = automation_hub, galaxy

[galaxy_server.galaxy]
url=https://galaxy.ansible.com/

[galaxy_server.automation_hub]
url=https://cloud.redhat.com/api/automation-hub/

auth_url=https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token

token=&amp;lt;your-token&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A bit of context first
&lt;/h2&gt;

&lt;p&gt;Before we continue, let's define what we mean (in this article) by update versus upgrade. &lt;/p&gt;

&lt;h3&gt;
  
  
  Updates
&lt;/h3&gt;

&lt;p&gt;An update to an existing JBoss EAP instance consists of the deployment of a series of fixes to the product’s code. Updates are provided to Red Hat customers through the &lt;a href="https://access.redhat.com/login?redirectTo=https%3A%2F%2Faccess.redhat.com"&gt;Red Hat Customer&lt;/a&gt; Portal. They contain a set of changes made against the JEE server code, either to fix an issue or address a security concern (or both). You need to use the JBoss CLI tool to deploy an update. However, as we’ll see soon, the &lt;code&gt;redhat.eap&lt;/code&gt; collection will take care of this for us.&lt;/p&gt;

&lt;p&gt;It’s important to note that such an update only brings fixes to the server. No functionality changes (unless required to resolve a problem) nor API changes are performed. Therefore, an update does not change the major version of JBoss EAP—only the minor version. For instance, bringing JBoss EAP 7.4.0 to 7.4.6 (but not to 7.5).&lt;/p&gt;

&lt;p&gt;Because an update to a more recent minor version only includes small changes, they rarely require modification to the applications hosted by JBoss EAP. They should be performed as quickly as possible in order to ensure the server can not be compromised by a known security issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Upgrades
&lt;/h3&gt;

&lt;p&gt;An upgrade is a more involved operation. Indeed, it comes with API changes and new features, meaning that, before being performed, the applications hosted by JBoss EAP should be tested against the new version and potentially adapted to work in this new context.&lt;/p&gt;

&lt;p&gt;Also, an upgrade to JBoss EAP is a change of major version (EAP 7.3 to 7.4). This cannot be achieved by updating the files of the currently installed software. A complete, new installation needs to be performed, and the configuration, along with the hosted apps, needs to be migrated to this new root folder.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This article focuses on the update and upgrade of the app server itself and, purposely, does not discuss configuration changes and application migration. On this front, too, the collection &lt;code&gt;redhat.eap&lt;/code&gt; provides some help by leveraging the JBoss migration tool. This scenario will be the topic of a follow-up article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Applying a cumulative patch
&lt;/h2&gt;

&lt;p&gt;Let’s consider the following scenario:&lt;/p&gt;

&lt;p&gt;A series of JBoss EAP 7.3.0 instances were freshly installed in order to perform tests before production. The tests were successful, and the team now wants to promote those servers from testing to preprod. The main requirement (regarding JBoss EAP) is to run the latest version of the server (7.3.10).&lt;/p&gt;

&lt;p&gt;Here is the playbook used to fully automate the installation process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: "Update EAP to latest {{ eap_patch_version }}"
  hosts: eap_servers
  vars:
    eap_version: 7.3.0
    eap_apply_cp: True
    eap_patch_version: 7.3.10
    eap_instance_name: eap73
  collections:
    - redhat.eap
  roles:
    - eap_install
    - eap_systemd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This playbook relies entirely on the two roles provided by the &lt;code&gt;redhat.eap&lt;/code&gt; collection, to install EAP and start the associated service. The only information required is the server (major) version provided by the variable &lt;code&gt;eap_version&lt;/code&gt;. We also configured the collection to update this minor version (&lt;code&gt;eap_patch_apply&lt;/code&gt; set to &lt;code&gt;true&lt;/code&gt;) to the latest available minor version (7.3.10). We also added a variable to change the name of the service running the server to eap73.&lt;/p&gt;

&lt;p&gt;Once this playbook has run successfully and Ansible has started the server, we can see that we are now running the latest version available of JBoss EAP 7.3, as proven by the following line of the server.log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# tail -f /opt/jboss_eap/jboss-eap-7.3/standalone/log/server.log
2023-03-01 11:25:29,413 INFO  [org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-6) WFLYJCA0001: Bound data source [java:jboss/datasources/ExampleDS]
2023-03-01 11:25:29,483 INFO  [org.jboss.as.patching] (MSC service thread 1-2) WFLYPAT0050: JBoss EAP cumulative patch ID is: jboss-eap-7.3.10.CP, one-off patches include: none
2023-03-01 11:25:29,494 WARN  [org.jboss.as.domain.management.security] (MSC service thread 1-2) WFLYDM0111: Keystore /opt/jboss_eap/jboss-eap-7.3/standalone/configuration/application.keystore not found, it will be auto generated on first use with a self signed certificate for host localhost
2023-03-01 11:25:29,499 INFO  [org.jboss.as.server.deployment.scanner] (MSC service thread 1-7) WFLYDS0013: Started FileSystemDeploymentService for directory /opt/jboss_eap/jboss-eap-7.3/standalone/deployments
2023-03-01 11:25:29,544 INFO  [org.wildfly.extension.undertow] (MSC service thread 1-3) WFLYUT0006: Undertow HTTPS listener https listening on [0:0:0:0:0:0:0:0]:8443
2023-03-01 11:25:29,593 INFO  [org.jboss.ws.common.management] (MSC service thread 1-5) JBWS022052: Starting JBossWS 5.3.0.Final-redhat-00001 (Apache CXF 3.3.12.redhat-00001)
2023-03-01 11:25:29,674 INFO  [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0212: Resuming server
2023-03-01 11:25:29,676 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: JBoss EAP 7.3.10.GA (WildFly Core 10.1.25.Final-redhat-00001) started in 2300ms - Started 306 of 560 services (355 services are lazy, passive or on-demand)
…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;By default, the collection installs the latest major version of JBoss EAP (7.4.0). As we will discuss upgrading to the next major version in the second part of this article, we have purposely installed the previous major version of the JEE server.&lt;/li&gt;
&lt;li&gt;If the playbook is run again, no changes are reported, as the collection ensures that the setup of JBoss EAP is idempotent.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Upgrading to the next major version of JBoss EAP
&lt;/h2&gt;

&lt;p&gt;Minor upgrades contain only fixes. The actual changes are minimal. Features themselves are not modified, and no new ones are added unless a security fix requires it. In short, this means users can perform such updates on their system without fearing side effects or issues for the hosted applications. However, upgrading JBoss EAP to the next major version is a completely different scenario.&lt;/p&gt;

&lt;p&gt;Let’s consider the following requirement. The JBoss EAP instances previously installed using Ansible have been targeted to be upgraded to 7.4 with the latest available minor version (7.4.10). Teams behind the hosted apps have tested and confirmed that no code changes are required; however, a plan is already in place if something goes wrong during the upgrade. Any instance having issues during the upgrade needs to downgrade and resume running the previous version.&lt;/p&gt;

&lt;p&gt;Let’s build a playbook implementing such a strategy. First, it will stop the currently running instance of JBoss EAP on the target, then install and start the new version, using the same configuration template as the previous server. And, if anything goes wrong during this process, the existing service will be started.&lt;/p&gt;

&lt;p&gt;Here is the playbook we will use to perform this migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: "Update EAP to latest {{ eap_patch_version }}"
  hosts: eap_servers
  vars:
    eap_offline_install: True
    eap_apply_cp: True
    eap_patch_version: 7.4.9
    eap_config_base: 'standalone.xml'
    eap_instance_name: eap74
  collections:
    - redhat.eap
  roles:
    - eap_systemd
  pre_tasks:
    - name: "Ensure previous version of EAP is not running"
      ansible.builtin.service:
        name: eap73
       state: stopped
  tasks:

    - block:
     - name: "Perform EAP {{ eap_patch_version }} installation"
       ansible.builtin.include_role:
         name: eap_install

     - name: "Ensure EAP service is deployed and running."
       ansible.builtin.include_role:
         name: eap_systemd

     - name: "Ensure EAP service is functional"
       ansible.builtin.include_role:
         name: eap_validation

     rescue:

     - name: "EAP upgrade failed, fallback to previous version"
       ansible.builtin.service:
         name: eap73
         state: running
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The playbook above implements the migration process we described above. First, it stops the existing JBoss EAP server running on the target. Then, it leverages the &lt;code&gt;redhat.eap&lt;/code&gt; collection again to install the new version and start it as a service. To ensure that this instance is functional, it runs the &lt;code&gt;eap_validation&lt;/code&gt; role, also provided by the collection, that performs some basic sanity checks against the service.&lt;/p&gt;

&lt;p&gt;Assuming nothing has failed during those three steps, the new server is running, and the migration has been completed successfully. If anything goes wrong, the new server is shut down, and the previous instance is restarted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This playbook is not idempotent and is aimed at being run only for migration purposes. This is both for the sake of simplicity and readability.&lt;/p&gt;

&lt;p&gt;Performing the upgrade and update without downtime&lt;/p&gt;

&lt;p&gt;Most of the time, updating and upgrading JBoss EAP will require restarting the service, which implies some downtime. However, if there is more than one instance of JBoss EAP to update, it is possible to use a powerful Ansible feature to avoid any downtime (assuming there is a smart proxy in front of the JBoss EAP farm, such as &lt;code&gt;httpd&lt;/code&gt; using &lt;code&gt;mod_cluster&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;By default, Ansible will try to connect to any hosts belonging to the &lt;code&gt;eap_servers&lt;/code&gt; group and perform the update and the upgrade in parallel. If everything goes according to plan, there is still a risk of downtime, as the server might be restarting at the same time. If anything goes wrong, most, if not all, will need to roll back to the previous version, leading to even more chances of downtime.&lt;/p&gt;

&lt;p&gt;However, this &lt;a href="https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_strategies.html"&gt;execution strategy&lt;/a&gt; can be configured by adding the keyword &lt;code&gt;serial&lt;/code&gt; to the playbook. This will configure how Ansible will operate on the list of servers to connect and execute by batch, only a subset of them at once. With this feature, we can implement the following approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update (or upgrade) on target;&lt;/li&gt;
&lt;li&gt;Update (or upgrade) one-third of the entire farm;&lt;/li&gt;
&lt;li&gt;Update (or upgrade) the rest of the targets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Such a strategy offers a lot of peace of mind; if the first machine to be targeted fails to update or upgrade, you can stop the process here and investigate what went wrong. The rest of the servers are still running without any risk of downtime. The same applies to the next batch. If something goes wrong with the first third of the servers, then most of the farm is still running the old version, uninterrupted.&lt;/p&gt;

&lt;p&gt;To implement this strategy in our upgrade playbook, we only need to add the attribute &lt;code&gt;serial&lt;/code&gt;. We valorize it using a list containing three values, as shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
- name: "Update EAP to latest {{ eap_patch_version }}"
  hosts: all
  serial:
    - 1
    - 30%
    - 70%
  vars:
    eap_offline_install: True
    eap_apply_cp: True
    eap_patch_version: 7.4.9
    eap_instance_name: eap74
  collections:
    - redhat.eap
  roles:
    - eap_install
    - eap_systemd
  pre_tasks:
    - name: "Ensure previous version of EAP is not running"
      ansible.builtin.service:
        name: eap73
      state: stopped
  tasks:
    - block:
        - name: "Perform EAP {{ eap_patch_version }} installation"
          ansible.builtin.include_role:
            name: eap_install
        - name: "Ensure EAP service is deployed and running."
          ansible.builtin.include_role:
            name: eap_systemd
        - name: "Ensure EAP service is functional"
          ansible.builtin.include_role:
            name: eap_validation
      rescue:
        - name: "EAP upgrade failed, fallback to previous version"
          ansible.builtin.service:
            name: eap73
            state: running
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the values within the serial property can indeed be a mix of integers (1) and percentages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With the heavy lifting of the server installation managed by the &lt;code&gt;redhat.eap&lt;/code&gt; collection and the primitives provided by Ansible, we have implemented a sound strategy to perform updates and upgrades on a potentially very large farm of instances.&lt;/p&gt;

&lt;p&gt;The two playbooks we displayed in this article are both short and simple to understand. Their content focuses only on the environment specificity (version executed, execution strategy), and the inner workings of EAP are fully encapsulated inside the collection, which provides peace of mind in what would typically be a complex operation and process.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
