How to provision WildFly with Ansible

Ansible is an innovative IT automation engine that automates cloud provisioning, configuration management, application deployment, intra-service orchestration, and many other IT needs. In this updated article we will learn how to provision and update a WildFly 32 application server distribution using playbooks.

Ansible Overview

Ansible is an open-source automation tool used for configuration management, application deployment, orchestration, and task automation. It simplifies IT operations by allowing users to automate repetitive tasks, manage infrastructure as code, and streamline complex workflows. Ansible uses simple YAML syntax and agentless architecture, making it easy to learn and use. It is widely adopted in DevOps practices for its scalability, flexibility, and efficiency in managing infrastructure and deploying applications across a variety of environments.

An Ansible playbook is a YAML file that defines a set of tasks to be executed on remote hosts managed by Ansible. Playbooks are the central component of Ansible’s configuration management system and are used to automate complex tasks and workflows. E

If you are new to Ansible, you can read this introduction Ansible Playbook Example for beginners

In the following section we will show how to provision a WildFly installation using Ansible. if you haven’t installed Ansible on your machine you can do it as follows (Fedora/RHEL machines):

sudo dnf install ansible-core

Provisioning WildFly with an Ansible Playbook

Playbooks in Ansible define a series of actions to run, and address particular sets of servers. In most cases, you will need to include also an Inventory file with the list of hosts where your playbook will run. For the sake of simplicity we will hardcode “localhost” as target host.

Within a Playbook you can define all the steps you need to install a JDK (needed for WildFly) and the application server itself. To simplify the creation of your Playbook you can install the following Ansible Collection which contains a set of Roles to provision WildFly:

ansible-galaxy collection install middleware_automation.wildfly

Ansible roles encapsulate reusable sets of tasks, handlers, templates, and variables that perform specific functions. By leveraging existing roles, playbook authors can avoid reinventing the wheel and reuse code that has been tested and validated by the community or their organization.

Finally, create the following wildfly.yml file ( choose any name that works for you):

- 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: 32.0.0.Final
    wildfly_java_package_name: java-17-openjdk
    wildfly_home: "/opt/wildfly-{{ wildfly_version }}"
    #wildfly_config_custom_file: standalone-ha.xml

    instance_http_ports: 8080  # Single port defined here
    app:
      name: 'info-1.2.war'
      url: 'https://drive.google.com/uc?export=download&id=13K7RCqccgH4zAU1RfOjYMehNaHB0A3Iq'
  collections:
    - middleware_automation.wildfly
  roles:
    - role: wildfly_install
  tasks:

    - name: "Set up for WildFly instance."
      ansible.builtin.include_role:
        name: wildfly_systemd
      vars:
        # ... rest of the variables within the role ...

    - name: "Wait for WildFly HTTP port to become available."
      ansible.builtin.wait_for:
        port: "{{ instance_http_ports }}"

    - name: "Checks that WildFly server is running and accessible."
      ansible.builtin.get_url:
        url: "http://localhost:{{ instance_http_ports }}/"
        dest: "/opt/{{ instance_http_ports }}"

This playbook will provision a WildFly installation using a set of built-in Roles:

You can customize the version, path and configuration file through the playbook variables:

  vars:
    wildfly_install_workdir: '/opt/'
    wildfly_config_base: standalone-ha.xml
    wildfly_version: 32.0.0.Final
    wildfly_java_package_name: java-17-openjdk
    wildfly_home: "/opt/wildfly-{{ wildfly_version }}"
    #wildfly_config_custom_file: standalone-ha.xml

If you want to provide a custom configuration file simply uncomment the line wildfly_config_custom_file and provide your own XML configuration.

In order to run the playbook you can execute from the Command Line:

ansible-playbook wildfly.yml --ask-become-pass

Enter your sudo password and check that the installation of WildFly completes successfully:

wildfly ansible tutorial step-by-step

After that, you can verify that WildFly is up and running by surfing on the default Welcome page at localhost:8080

wildfly with ansible provisioning

Updating and verifying the configuration

The WildFly Ansible Roles allow also to perform checks and updates on your existing configurations. For example, you can run CLI commands and check the result. You can also merge your configuration with Yaml files. This is available in WildFly as an idempotent way to update your configuration. Check this article to learn more: How to configure WildFly with YAML files

Let’s create a simple playbook to verify and update our configuration. Firstly, add the following verify.yml file:

- name: "verify"
  hosts: "{{ hosts_group_name | default('localhost') }}"
  become: yes
  vars:
    wildfly_install_workdir: '/opt/'
    wildfly_config_base: standalone-ha.xml
    wildfly_version: 32.0.0.Final
    wildfly_java_package_name: java-17-openjdk
    wildfly_home: "/opt/wildfly-{{ wildfly_version }}"
    wildfly_validation_debug: True
  gather_facts: false
  
  vars_files:
    - vars.yml
  collections:
    - middleware_automation.wildfly
  roles:
    - role: wildfly_validation 

As you can see, this playbook barely contains a set of variable definitions. To decouple the actual configuration checks/updates from the playbook, we are referring to the external vars.yml file which follows here:

Here you can find the vars.yml file which contains the logic:

---
wildfly_enable_yml_config: True
wildfly_config_base: 'standalone-ha.xml'
wildfly_yml_configs:
    - yaml_configuration.yml.j2
wildfly_validation_queries:
    - { query: ':read-attribute(name=product-version)', expected_result:  '32.0.0.Final', expected_result_undefined: false}
    - { query: '/socket-binding-group=standard-sockets/socket-binding=http:read-attribute(name=port, resolve-expressions=true)', expected_result:  '8080', expected_result_undefined: false}

Within this file we are enabling YAMl configuration updates ( contained in the file yaml_configuration.yml.j2). Also, we are verifying the outcome of two CLI commands.

The yaml_configuration.yml.j2 file simply sets a System Property into the configuration:

wildfly-configuration:
  system-property:
    JBOSS_ID:
      value: instance1

You can run this playbook as follows:

ansible-playbook wildfly.yml --ask-become-pass

Verify that the execution completes successfully and that your configuration is updated.

Conclusion

In conclusion, Ansible provides a powerful and efficient solution for provisioning and managing WildFly application servers. By leveraging Ansible’s automation capabilities, organizations can streamline the deployment process, ensure consistency across environments, and reduce the risk of human error.

You can find the source code for these playbooks here: https://github.com/fmarchioni/mastertheboss/tree/master/ansible/wildfly

Thanks to Romain Pelisse for providing insights on the WildFly Collection in this article: https://www.wildfly.org/news/2023/01/10/ansible-wildfly/