Skip to main content
Redhat Developers  Logo
  • Products

    Featured

    • Red Hat Enterprise Linux
      Red Hat Enterprise Linux Icon
    • Red Hat OpenShift AI
      Red Hat OpenShift AI
    • Red Hat Enterprise Linux AI
      Linux icon inside of a brain
    • Image mode for Red Hat Enterprise Linux
      RHEL image mode
    • Red Hat OpenShift
      Openshift icon
    • Red Hat Ansible Automation Platform
      Ansible icon
    • Red Hat Developer Hub
      Developer Hub
    • View All Red Hat Products
    • Linux

      • Red Hat Enterprise Linux
      • Image mode for Red Hat Enterprise Linux
      • Red Hat Universal Base Images (UBI)
    • Java runtimes & frameworks

      • JBoss Enterprise Application Platform
      • Red Hat build of OpenJDK
    • Kubernetes

      • Red Hat OpenShift
      • Microsoft Azure Red Hat OpenShift
      • Red Hat OpenShift Virtualization
      • Red Hat OpenShift Lightspeed
    • Integration & App Connectivity

      • Red Hat Build of Apache Camel
      • Red Hat Service Interconnect
      • Red Hat Connectivity Link
    • AI/ML

      • Red Hat OpenShift AI
      • Red Hat Enterprise Linux AI
    • Automation

      • Red Hat Ansible Automation Platform
      • Red Hat Ansible Lightspeed
    • Developer tools

      • Red Hat Trusted Software Supply Chain
      • Podman Desktop
      • Red Hat OpenShift Dev Spaces
    • Developer Sandbox

      Developer Sandbox
      Try Red Hat products and technologies without setup or configuration fees for 30 days with this shared Openshift and Kubernetes cluster.
    • Try at no cost
  • Technologies

    Featured

    • AI/ML
      AI/ML Icon
    • Linux
      Linux Icon
    • Kubernetes
      Cloud icon
    • Automation
      Automation Icon showing arrows moving in a circle around a gear
    • View All Technologies
    • Programming Languages & Frameworks

      • Java
      • Python
      • JavaScript
    • System Design & Architecture

      • Red Hat architecture and design patterns
      • Microservices
      • Event-Driven Architecture
      • Databases
    • Developer Productivity

      • Developer productivity
      • Developer Tools
      • GitOps
    • Secure Development & Architectures

      • Security
      • Secure coding
    • Platform Engineering

      • DevOps
      • DevSecOps
      • Ansible automation for applications and services
    • Automated Data Processing

      • AI/ML
      • Data Science
      • Apache Kafka on Kubernetes
      • View All Technologies
    • Start exploring in the Developer Sandbox for free

      sandbox graphic
      Try Red Hat's products and technologies without setup or configuration.
    • Try at no cost
  • Learn

    Featured

    • Kubernetes & Cloud Native
      Openshift icon
    • Linux
      Rhel icon
    • Automation
      Ansible cloud icon
    • Java
      Java icon
    • AI/ML
      AI/ML Icon
    • View All Learning Resources

    E-Books

    • GitOps Cookbook
    • Podman in Action
    • Kubernetes Operators
    • The Path to GitOps
    • View All E-books

    Cheat Sheets

    • Linux Commands
    • Bash Commands
    • Git
    • systemd Commands
    • View All Cheat Sheets

    Documentation

    • API Catalog
    • Product Documentation
    • Legacy Documentation
    • Red Hat Learning

      Learning image
      Boost your technical skills to expert-level with the help of interactive lessons offered by various Red Hat Learning programs.
    • Explore Red Hat Learning
  • Developer Sandbox

    Developer Sandbox

    • Access Red Hat’s products and technologies without setup or configuration, and start developing quicker than ever before with our new, no-cost sandbox environments.
    • Explore Developer Sandbox

    Featured Developer Sandbox activities

    • Get started with your Developer Sandbox
    • OpenShift virtualization and application modernization using the Developer Sandbox
    • Explore all Developer Sandbox activities

    Ready to start developing apps?

    • Try at no cost
  • Blog
  • Events
  • Videos

WildFly server configuration with Ansible collection for JCliff, Part 1

 

November 6, 2020
Romain Pelisse
Related topics:
DevOpsJavaLinux
Related products:
Red Hat Ansible Automation Platform

Share:

    This three-part series guides you through using Ansible to fine-tune a WildFly or Red Hat JBoss Enterprise Application Platform (JBoss EAP) server configuration. We will use the most recently released version of the Ansible collection for JCliff to extend Ansible's capabilities. The JCliff collection supports configuring several of the application server subsystems directly from Ansible.

    In Part 1, we will mostly focus on the groundwork and discuss all the steps required to be able to use JCliff within Ansible. Once properly installed, we'll use JCliff to configure WildFly's system_props subsystem, which lets us declare system variables in WildFly's server configuration. Once we have that foundation in place, we'll begin exploring more interesting configurations in Part 2 and Part 3.

    Note: See the Ansible documentation for more about Ansible collections.

    Using Ansible to fine-tune a WildFly server configuration

    Before we start setting up the Ansible playbook, let’s discuss what we want to achieve. Our use case is finetuning a WildFly server configuration, which means going beyond what Ansible's primitives can do for this software.

    It is easy to automate a WildFly installation using Ansible's built-in modules. You can use a package manager to install any necessary dependencies, create the required directory structure, set up the configuration files, and so on. However, you can't as easily fine-tune the WildFly server's configuration. The usual strategy of providing an Ansible template file for the server’s configuration is not suitable. Many server configurations live in the main configuration file (standalone.xml or standalone-full.xml). The server frequently accesses this file at runtime, altering the file contents at the same time. As a result, the main configuration file is not a good target for templating.

    Our goal is to provide a fine-tuned configuration to the WildFly server. Within the Ansible playbook, we want a way to define the server's required state. We also want to ensure that Ansible can monitor this state and spot any alterations to it. This is where the JCliff Ansible collection comes in.

    What is Ansible collection for JCliff?

    JCliff is a command-line interface (CLI) that lets us dynamically change a WildFly server's state. JCliff uses WildFly's JBoss CLI to update the server configuration at runtime. This tool is provided with the application server. Once the server has processed requests sent using the JBoss CLI tool, it ensures that the changes are recorded and updates the main configuration file, standalone.xml, accordingly.

    The new Ansible collection for JCliff (wildfly.jcliff) provides integration in the form of an Ansible module. Ansible uses the JCliff integration to verify that the WildFly server configuration is in the proper state. It also uses JCliff to update the server configuration if there are any discrepancies. JCliff builds the JBoss CLI queries that are required for these purposes. JCliff also helps Ansible remain idempotent, meaning that changes will only be applied if the configuration is not in the proper state.

    JCliff lets us express our requirements directly inside of the Ansible playbook. For this, we will use the jcliff: module, which is provided with the wildfly.jcliff collection.

    Note: If you want to know more about JCliff, see the article Managing JBoss EAP/WildFly using JCliff. This series builds on that article by showing you how to use JCliff's new Ansible collection format for packaging extensions within Ansible. Many thanks to my co-author for the original article, Andrew Block, for reviewing this series.

    Prerequisites for the demonstration

    Before diving into the demonstration, let's make sure that we have all of the prerequisites in place:

    • A Red Hat Enterprise Linux (RHEL), CentOS, or Fedora operating system.
    • A Java virtual machine for JDK 8 or higher.
    • Ansible (we recommend Ansible 2.9, but an older or more recent version should work).
    • WildFly 19 or higher, which should be installed and running on the system.

    Note: Ansible collection for JCliff includes a role to automate installing JCliff. Full support is currently available only for Linux and macOS, but work is emerging to support Windows.

    The Ansible playbook

    For our demonstration, we will start with a minimal, functional Ansible playbook. To keep the demonstration simple and easy to reproduce, we are running Ansible on a local system.

    ---
    
    - hosts: localhost
    
      gather_facts: true
    
      vars:
    
      tasks:
    

    Let's verify that Ansible is properly installed on the control node and that the playbook completes successfully:

    $ ansible-playbook playbook.yml
    
    [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
    
    PLAY [localhost] ***********************************************************************************************************************
    
    TASK [Gathering Facts] *****************************************************************************************************************
    
    ok: [localhost]
    
    PLAY RECAP *****************************************************************************************************************************
    
    localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
    

    So far, everything works. Note that we set the gather_facts property to true. This setting allows Ansible to gather information about the system. Soon, Ansible will use this information to install JCliff.

    Note: While gathering facts is not a hard requirement for the JCliff Ansible collection, you might have to provide the additional variables yourself if you choose to disable this setting.

    Installing Ansible collection for JCliff

    We are ready to install the Ansible collection for JCliff. First, we'll use the ansible-galaxy tool (which is included with Ansible by default) to install the wildfly.jcliff module:

    # ansible-galaxy collection install wildfly.jcliff
    
    Process install dependency map
    
    Starting collection install process
    
    Installing 'wildfly.jcliff:0.0.2' to '/root/.ansible/collections/ansible_collections/wildfly/jcliff'
    

    Locate the JBOSS_HOME variable

    As I previously mentioned, the JCliff Ansible collection comes with a role that automatically installs JCliff. All we have to do is add the required instructions to our Ansible playbook. In particular, JCliff needs the JBOSS_HOME environment variable to locate the WildFly server on a target system. Let's retrieve the server location from this environment variable before going further:

    ---
    
    - hosts: localhost
    
      gather_facts: true
    
      vars:
    
        jboss_home: "{{ lookup('env','JBOSS_HOME') }}"
    
      collections:
    
        - wildfly.jcliff
    
      roles:
    
        - jcliff
    
      tasks:
    

    Note the following:

    • The variable jboss_home is defined with the value of the environment variable called JBOSS_HOME which ensure that there is no discrepancy between them.
    • This playbook requires the wildfly.jcliff collection, which we've just installed locally.
    • The Ansible playbook imports the jcliff role from the wildfly.jcliff collection. This role takes care of installing JCliff itself on the system.

    Next, we'll run the Ansible playbook with the instructions and information required to install JCliff.

    Run the playbook to install the JCliff CLI

    Running the Ansible playbook imports the jcliff role and performs the following tasks to install the JCliff CLI:

    # ansible-playbook playbook.yml
    
    [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
    
    PLAY [localhost] ***********************************************************************************************************************
    
    TASK [Gathering Facts] *****************************************************************************************************************
    
    ok: [localhost]
    
    TASK [wildfly.jcliff.jcliff : Collect Supported Operating Systems] *********************************************************************
    
    ok: [localhost] => (item={u'key': u'homebrew', u'value': [u'MacOSX']})
    
    ok: [localhost] => (item={u'key': u'rpm', u'value': [u'Fedora', u'CentOS', u'RedHat']})
    
    TASK [wildfly.jcliff.jcliff : Verify supported Operating Systems] **********************************************************************
    
    ok: [localhost]
    
    TASK [wildfly.jcliff.jcliff : Install JCliff using HomeBrew] ***************************************************************************
    
    skipping: [localhost]
    
    TASK [wildfly.jcliff.jcliff : Install JCliff using RPM] ********************************************************************************
    
    included: /root/.ansible/collections/ansible_collections/wildfly/jcliff/roles/jcliff/tasks/install_rpm.yml for localhost
    
    TASK [wildfly.jcliff.jcliff : Add JCliff Yum Repository (RedHat)] **********************************************************************
    
    ok: [localhost]
    
    TASK [wildfly.jcliff.jcliff : Test if package jcliff is already installed] *************************************************************
    
    fatal: [localhost]: FAILED! => {"changed": false, "cmd": ["rpm", "-q", "jcliff"], "delta": "0:00:00.489702", "end": "2020-08-17 08:54:34.190992", "msg": "non-zero return code", "rc": 1, "start": "2020-08-17 08:54:33.701290", "stderr": "", "stderr_lines": [], "stdout": "package jcliff is not installed", "stdout_lines": ["package jcliff is not installed"]}
    
    TASK [wildfly.jcliff.jcliff : Ensure JCliff is installed] ******************************************************************************
    
    changed: [localhost]
    
    TASK [wildfly.jcliff.jcliff : Install Jcliff using standalone binary] ******************************************************************
    
    skipping: [localhost]
    
    PLAY RECAP *****************************************************************************************************************************
    
    localhost                  : ok=6    changed=1    unreachable=0    failed=0    skipped=2    rescued=1    ignored=0
    

    The playbook ran the jcliff role. The new role noticed that JCliff was not installed on the system and installed the necessary software.

    Verify the JCliff installation

    Now, let's verify that JCliff is installed:

    # jcliff --version
    
    No JBOSS_HOME provided, aborting...
    

    JCliff is installed, but (as I previously noted), it needs us to define the JBOSS_HOME variable to be functional:

    $ export JBOSS_HOME=/path/to/wildfly/home

    After we've exported the environment variable, try re-running the command:

    # jcliff
    
    Jcliff version 2.12.5
    
    Usage:
    
        jcliff [options] file(s)
    
    where the options are:
    
      --cli=Path : jboss-cli.sh. Defaults to
    
                   /usr/share/jbossas/bin/jboss-cli.sh
    
      --controller=host       : EAP6 host. Defaults to localhost.
    
      --user=username         : EAP6 admin user name
    
      --password=pwd          : EAP6 admin password
    
      --ruledir=Path          : Location of jcliff rules.
    
      --noop                  : Read-only mode
    
      --json                  : Use json to parse input files
    
      -v                      : Verbose output
    
      --timeout=timeout       : Command timeout in milliseconds
    
      --output=Path           : Log output file
    
      --reload                : Reload after each subsystem configuration if required
    
      --waitport=waitport     : Wait this many seconds for the port to be opened
    
      --nobatch               : Don't use batch mode of jboss-cli
    
      --redeploy              : Redeploy all apps
    
      --reconnect-delay=delay : Wait this many milliseconds after a :reload for the server to restart
    
      --leavetmp              : Don't erase temp files
    
      --pre=str               : Prepend str to all commands (can be used for domain mode support)
    

    JCliff is now installed and fully operational.

    Verify idempotency

    There is one last thing to do before the setup is complete. We must ensure that our Ansible playbooks are idempotent. In this context, that means the tasks described in a playbook won’t be performed again if the system is already in the appropriate state. To check this, run the playbook again and verify that no more changes are being applied:

    # ansible-playbook  playbook.yml
    
    PLAY [localhost] *****************************************************************************************************************************************************************************
    
    TASK [Gathering Facts] ***********************************************************************************************************************************************************************
    
    ok: [localhost]
    
    TASK [wildfly.jcliff.jcliff : Collect Supported Operating Systems] ***************************************************************************************************************************
    
    ok: [localhost] => (item={u'key': u'homebrew', u'value': [u'MacOSX']})
    
    ok: [localhost] => (item={u'key': u'rpm', u'value': [u'Fedora', u'CentOS', u'RedHat']})
    
    TASK [wildfly.jcliff.jcliff : Verify supported Operating Systems] ****************************************************************************************************************************
    
    ok: [localhost]
    
    TASK [wildfly.jcliff.jcliff : Install JCliff using HomeBrew] *********************************************************************************************************************************
    
    skipping: [localhost]
    
    TASK [wildfly.jcliff.jcliff : Install JCliff using RPM] **************************************************************************************************************************************
    
    included: /root/.ansible/collections/ansible_collections/wildfly/jcliff/roles/jcliff/tasks/install_rpm.yml for localhost
    
    TASK [wildfly.jcliff.jcliff : Add JCliff Yum Repository (RedHat)] ****************************************************************************************************************************
    
    ok: [localhost]
    
    TASK [wildfly.jcliff.jcliff : Test if package jcliff is already installed] *******************************************************************************************************************
    
    ok: [localhost]
    
    TASK [wildfly.jcliff.jcliff : Install Jcliff using standalone binary] ************************************************************************************************************************
    
    skipping: [localhost]
    
    PLAY RECAP ***********************************************************************************************************************************************************************************
    
    localhost                  : ok=6    changed=0    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0
    

    We have completed the setup to integrate our Ansible playbook with JCliff. Now, we are ready to start using the jcliff: module to fine-tune our WildFly server configuration.

    Define system variables in the WildFly server configuration

    We'll start by using JCliff to add system variables to WildFly's server configuration. It’s not the most complex functionality, but it's a good way to confirm that everything is working:

    ---
    
    - hosts: localhost
    
      gather_facts: true
    
      vars:
    
        jboss_home: "{{ lookup('env','JBOSS_HOME') }}"
    
      collections:
    
        - wildfly.jcliff
    
      roles:
    
        - jcliff
    
      tasks:
    

    The configuration so far is straightforward. The JCliff CLI only requires the path to the WildFly server's home directory, which we defined in the jboss_home variable. After locating the home variable, JCliff uses the script provided with WildFly (${JBOSS_HOME}/bin/jboss-cli.sh) to communicate with the WildFly server.

    Now, we want to begin our custom configuration. Most WildFly configurations are defined as subsystems, and JCliff has a list of these subsystems. We will start with something simple: The system_props subsystem, which we'll use to declare system variables in the WildFly server configuration:

        - jcliff:
    
            wfly_home: "{{ jboss_home }}"
    
            subsystems:
    
              - system_props:
    
                  - name: jcliff.enabled
    
                    value: 'enabled.plus'
    

    Re-run the Ansible playbook and see what happens:

    # ansible-playbook playbook.yml
    
    PLAY [localhost] *****************************************************************************************************************************************************************************
    
    TASK [Gathering Facts] ***********************************************************************************************************************************************************************
    
    ok: [localhost]
    
    TASK [wildfly.jcliff.jcliff : Collect Supported Operating Systems] ***************************************************************************************************************************
    
    ok: [localhost] => (item={u'key': u'homebrew', u'value': [u'MacOSX']})
    
    ok: [localhost] => (item={u'key': u'rpm', u'value': [u'Fedora', u'CentOS', u'RedHat']})
    
    TASK [wildfly.jcliff.jcliff : Verify supported Operating Systems] ****************************************************************************************************************************
    
    ok: [localhost]
    
    TASK [wildfly.jcliff.jcliff : Install JCliff using HomeBrew] *********************************************************************************************************************************
    
    skipping: [localhost]
    
    TASK [wildfly.jcliff.jcliff : Install JCliff using RPM] **************************************************************************************************************************************
    
    included: /root/.ansible/collections/ansible_collections/wildfly/jcliff/roles/jcliff/tasks/install_rpm.yml for localhost
    
    TASK [wildfly.jcliff.jcliff : Add JCliff Yum Repository (RedHat)] ****************************************************************************************************************************
    
    ok: [localhost]
    
    TASK [wildfly.jcliff.jcliff : Test if package jcliff is already installed] *******************************************************************************************************************
    
    ok: [localhost]
    
    TASK [wildfly.jcliff.jcliff : Install Jcliff using standalone binary] ************************************************************************************************************************
    
    skipping: [localhost]
    
    TASK [jcliff] ********************************************************************************************************************************************************************************
    
    changed: [localhost]
    
    PLAY RECAP ***********************************************************************************************************************************************************************************
    
    localhost                  : ok=7    changed=1    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0
    

    Everything seems to be running smoothly. Ansible noticed that the variables we defined were missing from the server’s initial configuration and added them. All of this happened thanks to JCliff communicating with the server (via the JBoss CLI).

    To confirm that the variables are defined in the WildFly configuration, run the following JBoss CLI query:

    # ${JBOSS_HOME}/bin/jboss-cli.sh --connect --command='/system-property=jcliff.enabled:read-resource'
    
    {
    
        "outcome" => "success",
    
        "result" => {"value" => "enabled.plus"}
    
    }
    

    Let's be thorough and verify one of the promises of JCliff. We said earlier that the WildFly server's XML configuration would be automatically updated. Here is the confirmation that it has been:

    ...
    
     </extensions>
    
        <system-properties>
    
            <property name="jcliff.enabled" value="enabled.plus"/>
    
        </system-properties>
    
        <management>
    
    ...
    

    Everything is working as expected. JCliff can communicate with the WildFly server, and it can update the server configuration.

    Conclusion

    We've completed the basic setup. In Part 2, we will go deeper into the features offered by the Ansible collection for JCliff. We'll cover how to deploy new JDBC drivers along with defining new data sources. We will also deploy applications inside the application server.

    Last updated: February 5, 2024

    Recent Posts

    • How Kafka improves agentic AI

    • How to use service mesh to improve AI model security

    • How to run AI models in cloud development environments

    • How Trilio secures OpenShift virtual machines and containers

    • How to implement observability with Node.js and Llama Stack

    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Products

    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform

    Build

    • Developer Sandbox
    • Developer Tools
    • Interactive Tutorials
    • API Catalog

    Quicklinks

    • Learning Resources
    • E-books
    • Cheat Sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site Status Dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Report a website issue