How it works

The parts of an installation, what happens at a launch, and where data is kept

  1. Architecture
    1. Built with
  2. What happens when you launch a form
  3. Where things are stored

Architecture

AnsibleForms is a Node.js server that serves the web application and a REST API, backed by a MySQL database. It reads forms from YAML files and runs nothing itself: it hands each job to a runner. A playbook goes to one of your RTE (runtime environment) containers, which runs ansible-playbook, and a template or job goes to AWX, AAP, Ascender, Semaphore, Rundeck or Jenkins:

AnsibleForms architecture The browser and an optional MCP client talk to the AnsibleForms server. The server stores its data in MySQL and in the persistent folder, and connects to data sources, secret stores, git repositories, login providers, notification channels, syslog servers and an optional model provider. Its runners hand each playbook to one of one or more RTE containers over a WebSocket each, which run ansible-playbook and send the output back to the server, and each template or job to AWX, AAP, Ascender, Semaphore, Rundeck or Jenkins. Browser forms, designer, jobs, chat MCP client optional AnsibleForms server Node.js / Express Web app and REST API Form engine, expressions Workflows, schedules MCP server (optional) Runners hand each job to its runner Data sources databases, REST APIs, files Secret stores HashiCorp Vault, CyberArk Git repositories forms, playbooks, config Login providers LDAP, Entra ID, OIDC Notification channels mail, Slack, Teams, webhooks Syslog servers the log, the audit trail Model provider optional, chat assistant Persistent folder config, forms, playbooks MySQL / MariaDB jobs, users, credentials RTE containers run ansible-playbook AWX / AAP / Ascender Semaphore, Rundeck, Jenkins playbooks, WebSocket templates, jobs

The components in the diagram each have a role of their own:

Component Role
Browser The Vue web application: the forms, the Designer, the job history and the settings
AnsibleForms server Evaluates the forms, records the jobs, runs the workflows and the schedules, hands each job to its runner and follows it, and serves the REST API
Runners Where jobs run, added under Connections > Runners: a form names one with runner: <name>, or uses the default runner of its type (see Runners)
RTE containers One or more runtime environment containers, the same server started with AF_ROLE=rte: each runs ansible-playbook for ansible forms, with the python libraries and collections of its image, and sends the output and the final status back to the server over one WebSocket, without database credentials (see How the RTE runs)
AWX / AAP / Ascender, Semaphore, Rundeck, Jenkins Runners for templates and jobs: AWX forms launch a job or workflow template, Semaphore, Rundeck and Jenkins forms launch one of their jobs, and the server follows its output
MySQL / MariaDB Holds the jobs and their output, the users, the credentials and the connections; only the server reads and writes it
Persistent folder Holds config.yaml, the form files, the playbooks, the logs and the backups
Data sources Fill the fields: database queries, REST APIs, files and other functions
Secret stores Supply the user and password of a credential at use time, see Secret stores
Git repositories Keep the forms, the playbooks and config.yaml under version control
Login providers Sign the users in: LDAP, Entra ID and OIDC, next to the local users
Notification channels Carry the notifications and the approval requests: mail, Slack, Microsoft Teams, Telegram or a webhook
Syslog servers Receive the log and the audit trail as they are written, see Syslog
MCP client, chat Optional, both off by default: the MCP server and the chat assistant, which needs a model provider

By default one container runs the server, web app and background work together, next to one RTE. For several app nodes behind a load balancer, a worker that runs the background work, and more RTEs, see Scaling.

Built with

The server and the web interface are built on these components:

Part Technology
Server Node.js and Express
Database MySQL or MariaDB
Web interface Vue 3, with Bootstrap 5 and Font Awesome

What happens when you launch a form

A launch goes through the same steps whether it comes from the browser or from the REST API:

  1. Load : the server sends only the forms the user’s roles allow, and evaluates server expressions
  2. Submit : the browser turns the field values into extravars and posts them to POST /api/v2/job
  3. Check : the server reloads the form for the user’s roles and, with launch validation on, checks the values
  4. Record : the job is stored with status running, and its id is added to the extravars as __jobid__
  5. Approve : a form with an approval point waits until an approver accepts the job
  6. Credentials : for a playbook, the app (never the RTE) reads the form’s credentials from the database or a secret store
  7. Run : the job goes to its runner, the one the form names with runner: or the default of its type. For a playbook, the app sends the job to its RTE over the RTE’s WebSocket, with its credentials sealed for it, and the RTE runs ansible-playbook (see How the RTE runs), and AWX, AAP, Ascender, Semaphore, Rundeck or Jenkins runs a template or a job. A workflow runs its nodes, each as a job of its own on its own runner
  8. Follow : the server saves the output in the database as it arrives, sent by the RTE over its socket for a playbook, or read from the other runners. The form page re-reads the job every two seconds, and the Jobs page follows it live as the server announces each change
  9. End : the job gets its final status, and its notifications go out by mail and to its notification channels when the form asks for them

Where things are stored

AnsibleForms keeps its state in two places: the MySQL database and the persistent folder. Back up both.

In the database

The database, AnsibleForms, is created at the first start (unless ALLOW_SCHEMA_CREATION is 0) and holds:

  • the jobs, their extravars and their output, the schedules and the stored jobs
  • the local users, the groups and the API tokens
  • the credentials, encrypted with ENCRYPTION_SECRET, and the secret store connections
  • the runners, the notification channels (mail included), the syslog servers, and the LDAP, SSO, repository and chat assistant settings
  • the audit log

In the persistent folder

It is /app/dist/persistent in the image and server/persistent from source; each path has its own variable:

Default path Variable Contents
config.yaml CONFIG_PATH The categories, the roles and the constants
forms/ FORMS_FOLDER_PATH The form files, .yaml or .yml, in subfolders if you like
playbooks/ ANSIBLE_PATH The playbooks of ansible forms, and their working directory
repositories/ REPO_PATH The clones of the git repositories
forms_backups/ FORMS_BACKUP_PATH The copies the Designer makes before it saves
backups/ BACKUP_PATH The database backups
uploads/ UPLOAD_PATH The files uploaded through file fields
logs/ LOG_PATH ansibleforms.log and ansibleforms.errors.log
certificates/ HTTPS_CERT, HTTPS_KEY The certificate and key, when HTTPS is 1
.env   The environment variables saved from the settings pages (unless ALLOW_ENV_EDIT is 0)

The generated SSH key lives in HOME_PATH, outside the persistent folder by default.