Skip to content

feat: Add NGINX Agent config template #750

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ BREAKING CHANGES:

FEATURES:

- Add support for templating the entire NGINX Agent configuration file.
- Add support for installing and configuring the NGINX Plus HA keepalived package.
- Add validation tasks to check the Ansible version, the Jinja2 version, whether the required Ansible collections for this role are installed, and whether you are trying to install a valid NGINX module.
- Add support for installing NGINX Open Source on Alpine Linux 3.20.
Expand Down
112 changes: 100 additions & 12 deletions defaults/main/agent.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,107 @@
---
# Install NGINX Agent.
# Install the NGINX Agent.
# Requires access to either the NGINX stub_status or the NGINX Plus REST API.
nginx_agent_enable: false

# Specify the NGINX Agent data plane key/token.
# This is required to authenticate the NGINX Agent with the NGINX One SaaS control plane available in F5 Distributed Cloud.
# Default is null.
nginx_agent_data_plane_key: null

# Specify the control plane server host and port.
########################################################################################################################
# The following parameters let you configure the static configuration file of NGINX Agent. #
# By default, the config produced is as close a match to the default config provided by NGINX Agent upon installation. #
########################################################################################################################

# Configure the NGINX Agent.
nginx_agent_configure: false

# Specify the NGINX Agent API host and port. Optionally, specify the path to the cert and key.
# Default is not enabled.
# nginx_agent_api:
# host: 127.0.0.1
# port: 8081
# cert: /path/to/cert
# key: /path/to/key

# Specify the control plane server host, port, and data plane key/token.
# The data plane key is required to authenticate NGINX Agent with the NGINX One SaaS control plane available in F5 Distributed Cloud.
# Default is the NGINX One SaaS control plane available in F5 Distributed Cloud.
nginx_agent_server_host: agent.connect.nginx.com
nginx_agent_server_port: 443
# nginx_agent_server:
# host: agent.connect.nginx.com
# port: 443
# data_plane_key: ''

# Enable TLS communication between data plane and control plane.
# Optionally, specify the path to the TLS certificate, key, and CA certificate to enable mTLS.
# nginx_agent_tls:
# enable: true
# skip_verify: false
# cert: /path/to/cert
# key: /path/to/key
# ca: /path/to/ca

# Specify the log level and path.
# Default is info for the log level and /var/log/nginx-agent/ for the log path.
nginx_agent_log:
level: info
path: /var/log/nginx-agent/

# Specify NGINX specific options within NGINX Agent.
# Default is to not exclude any logs, to use the default socket path and to not treat warnings as errors.
nginx_agent_nginx:
exclude_logs: '""'
socket: '"unix:/var/run/nginx-agent/nginx.sock"'
# treat_warnings_as_errors: false

# Specify how often NGINX Agent polls the dataplane.
# Default is 30s for poll interval and 24h for report interval.
nginx_agent_dataplane_status:
poll_interval: 30s
report_interval: 24h

# Specify how often NGINX Agent reports metrics to the control plane.
# Default is 20 for the buffer/bulk size, 1m for report interval, 15s for collection interval and aggregated for mode.
nginx_agent_metrics:
bulk_size: 20
report_interval: 1m
collection_interval: 15s
mode: aggregated

# NGINX Open Source default config paths.
# Default can be seen below.
# nginx_agent_config_dirs: '"/etc/nginx:/usr/local/etc/nginx:/usr/share/nginx/modules"'

# Internal NGINX Agent queue size.
# Default is 100.
# nginx_agent_queue_size: 100

# NGINX Agent features.
# Default is an empty list. See https://docs.nginx.com/nginx-agent/configuration/configuration-overview/ for more details.
# nginx_agent_features: []

# NGINX Agent extensions.
# Default is an empty list. To enable NGINX App Protect reporting within NGINX Agent, use the 'nginx-app-protect' extension as below.
# nginx_agent_extensions: ['nginx-app-protect']

# NGINX Agent NGINX App Protect settings.
# Default is not enabled.
# nginx_agent_app_protect:
# report_interval: 15s
# precompiled_publication: true


#############################################################################################
# The following parameters let you configure the dynamic configuration file of NGINX Agent. #
# By default, nothing is configured. #
#############################################################################################

# Configure the NGINX Agent dynamic configuration file.
# NOTE: This will only run if the NGINX Agent dynamic configuration file has not yet been modified externally.
# If you want to force push a dynamic configuration file, use the 'nginx_agent_configure_dynamic_force' parameter below.
# Default is false.
nginx_agent_configure_dynamic: false
# Force pushing a new dynamic configuration file to NGINX Agent.
# NOTE: This will overwrite any changes made to the dynamic configuration file by a control plane, and might lead to unexpected behavior.
# Default is false.
nginx_agent_configure_dynamic_force: false

# Enable TLS communication between data plane and control plane
# Default is true.
nginx_agent_tls_enable: true
nginx_agent_tls_skip_verify: false
# Specify the NGINX Agent instance group and tags.
# nginx_agent_instance_group: my_instance_group
# nginx_agent_tags: [ansible, dev, qa]
2 changes: 1 addition & 1 deletion handlers/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
- name: (Handler) Start NGINX Agent
ansible.builtin.service:
name: nginx-agent
state: started
state: restarted
enabled: true

- name: (Handler) Start logrotate
Expand Down
22 changes: 21 additions & 1 deletion molecule/agent/converge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,24 @@
name: ansible-role-nginx
vars:
nginx_agent_enable: true
nginx_agent_data_plane_key: "{{ lookup('env', 'AGENT_DATA_PLANE_KEY') }}"
nginx_agent_configure: true
nginx_agent_server:
host: agent.connect.nginx.com
port: 443
data_plane_key: "{{ lookup('env', 'AGENT_DATA_PLANE_KEY') }}"
nginx_agent_tls:
enable: true
skip_verify: false
nginx_agent_nginx:
exclude_logs: '""'
socket: '"unix:/var/run/nginx-agent/nginx.sock"'
treat_warnings_as_errors: false
nginx_agent_config_dirs: '"/etc/nginx:/usr/local/etc/nginx:/usr/share/nginx/modules"'
nginx_agent_queue_size: 100
nginx_agent_extensions: ['metrics']
nginx_agent_api:
host: 127.0.0.1
port: 8081
nginx_agent_configure_dynamic: true
nginx_agent_instance_group: ansible_instance_group
nginx_agent_tags: ['ansible', 'dev']
52 changes: 40 additions & 12 deletions tasks/agent/install-agent.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
---
- name: (Alpine Linux/Debian/SLES OSs) Install NGINX Agent nstat prerequisite
ansible.builtin.package:
name: iproute2
state: present
when: ansible_facts['os_family'] in ['Alpine', 'Debian', 'Suse']

- name: (Red Hat OSs) Install NGINX Agent nstat prerequisite
ansible.builtin.package:
name: iproute
state: present
when: ansible_facts['os_family'] == "RedHat"

- name: Manage NGINX Agent repository
ansible.builtin.include_tasks: "{{ role_path }}/tasks/agent/setup-{{ ansible_facts['os_family'] | lower }}.yml"
when: ansible_facts['os_family'] in ['Alpine', 'Debian', 'RedHat', 'Suse']
Expand All @@ -8,18 +20,34 @@
name: nginx-agent
state: present

- name: Configure NGINX Agent
ansible.builtin.blockinfile:
backup: true
- name: Dynamically generate NGINX Agent static configuration file
ansible.builtin.template:
src: nginx-agent/nginx-agent.conf.j2
dest: /etc/nginx-agent/nginx-agent.conf
mode: "0644"
path: /etc/nginx-agent/nginx-agent.conf
block: |
server:
{{ ("token: " + nginx_agent_data_plane_key) if nginx_agent_data_plane_key is defined and nginx_agent_data_plane_key | length > 0 }}
host: {{ nginx_agent_server_host }}
grpcPort: {{ nginx_agent_server_port }}
backup: true
when: nginx_agent_configure | bool
notify: (Handler) Start NGINX Agent

- name: Check if the NGINX Agent dynamic configuration file has been modified
ansible.builtin.lineinfile:
path: /var/lib/nginx-agent/agent-dynamic.conf
line: '# agent-dynamic.conf'
state: present
check_mode: true
changed_when: false
when:
- nginx_agent_configure_dynamic | bool
- not nginx_agent_configure_dynamic_force | bool
register: default_conf

tls:
enable: {{ nginx_agent_tls_enable }}
skip_verify: {{ nginx_agent_tls_skip_verify }}
- name: Dynamically generate NGINX Agent dynamic configuration file if it has not been externally modified
ansible.builtin.template:
src: nginx-agent/agent-dynamic.conf.j2
dest: "{{ (ansible_facts['system'] | lower is not search('bsd')) | ternary('/var/lib/nginx-agent/agent-dynamic.conf', '/var/db/nginx-agent/agent-dynamic.conf') }}"
mode: "0644"
backup: true
when:
- nginx_agent_configure_dynamic | bool
- (default_conf['msg'] is defined and default_conf['msg'] != 'line added') or nginx_agent_configure_dynamic_force | bool
notify: (Handler) Start NGINX Agent
11 changes: 11 additions & 0 deletions templates/nginx-agent/agent-dynamic.conf.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{{ ansible_managed | comment }}

{% if nginx_agent_instance_group is defined %}
instance_group: {{ nginx_agent_instance_group }}
{% endif %}
{% if nginx_agent_tags is defined %}
tags:
{% for tag in nginx_agent_tags %}
- {{ tag }}
{% endfor %}
{% endif %}
123 changes: 123 additions & 0 deletions templates/nginx-agent/nginx-agent.conf.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
{{ ansible_managed | comment }}

{% if nginx_agent_server is defined and nginx_agent_server is mapping %}
server:
{% if nginx_agent_server['data_plane_key'] is defined %}
token: {{ nginx_agent_server['data_plane_key'] }}
{% endif %}
host: {{ nginx_agent_server['host'] }}
grpcPort: {{ nginx_agent_server['port'] }}
{% endif %}

{% if nginx_agent_tls is defined and nginx_agent_tls is mapping %}
tls:
enable: {{ nginx_agent_tls['enable'] | bool }}
skip_verify: {{ nginx_agent_tls['skip_verify'] | bool }}
{% if nginx_agent_tls['cert'] is defined %}
cert: {{ nginx_agent_tls['cert'] }}
{% endif %}
{% if nginx_agent_tls['key'] is defined %}
key: {{ nginx_agent_tls['key'] }}
{% endif %}
{% if nginx_agent_tls['ca'] is defined %}
ca: {{ nginx_agent_tls['ca'] }}
{% endif %}
{% endif %}

{% if nginx_agent_log is defined and nginx_agent_log is mapping %}
log:
{% if nginx_agent_log['level'] is defined %}
level: {{ nginx_agent_log['level'] }}
{% endif %}
{% if nginx_agent_log['path'] is defined %}
path: {{ nginx_agent_log['path'] }}
{% endif %}
{% endif %}

{% if nginx_agent_nginx is defined and nginx_agent_nginx is mapping %}
nginx:
{% if nginx_agent_nginx['exclude_logs'] is defined %}
exclude_logs: {{ nginx_agent_nginx['exclude_logs'] }}
{% endif %}
{% if nginx_agent_nginx['socket'] is defined %}
socket: {{ nginx_agent_nginx['socket'] }}
{% endif %}
{% if nginx_agent_nginx['treat_warnings_as_errors'] is defined and nginx_agent_nginx['treat_warnings_as_errors'] is boolean %}
treat_warnings_as_errors: {{ nginx_agent_nginx['treat_warnings_as_errors'] | ternary('true', 'false') }}
{% endif %}
{% endif %}

{% if nginx_agent_dataplane_status is defined and nginx_agent_dataplane_status is mapping %}
dataplane:
status:
{% if nginx_agent_dataplane_status['poll_interval'] is defined %}
poll_interval: {{ nginx_agent_dataplane_status['poll_interval'] }}
{% endif %}
{% if nginx_agent_dataplane_status['report_interval'] is defined %}
report_interval: {{ nginx_agent_dataplane_status['report_interval'] }}
{% endif %}
{% endif %}

{% if nginx_agent_metrics is defined and nginx_agent_metrics is mapping %}
metrics:
{% if nginx_agent_metrics['bulk_size'] is defined and nginx_agent_metrics['bulk_size'] is number %}
bulk_size: {{ nginx_agent_metrics['bulk_size'] }}
{% endif %}
{% if nginx_agent_metrics['report_interval'] is defined %}
report_interval: {{ nginx_agent_metrics['report_interval'] }}
{% endif %}
{% if nginx_agent_metrics['collection_interval'] is defined %}
collection_interval: {{ nginx_agent_metrics['collection_interval'] }}
{% endif %}
{% if nginx_agent_metrics['mode'] is defined %}
mode: {{ nginx_agent_metrics['mode'] }}
{% endif %}
{% endif %}

{% if nginx_agent_config_dirs is defined %}
config_dirs: {{ nginx_agent_config_dirs }}
{% endif %}

{% if nginx_agent_queue_size is defined and nginx_agent_queue_size is number %}
queue_size: {{ nginx_agent_queue_size }}
{% endif %}

{% if nginx_agent_features is defined and nginx_agent_features is not mapping and nginx_agent_features is not string and nginx_agent_features | length > 0 %}
features:
{% for feature in nginx_agent_features %}
{{ "- " + feature }}
{% endfor %}
{% endif %}

{% if nginx_agent_extensions is defined and nginx_agent_extensions is not mapping and nginx_agent_extensions is not string and nginx_agent_extensions | length > 0 %}
extensions:
{% for extension in nginx_agent_extensions %}
{{ "- " + extension }}
{% endfor %}
{% endif %}

{% if nginx_agent_app_protect is defined and nginx_agent_app_protect is mapping %}
nginx_app_protect:
{% if nginx_agent_app_protect['report_interval'] is defined %}
report_interval: {{ nginx_agent_app_protect['report_interval'] }}
{% endif %}
{% if nginx_agent_app_protect['precompiled_publication'] is defined and nginx_agent_app_protect['precompiled_publication'] is boolean %}
precompiled_publication: {{ nginx_agent_app_protect['precompiled_publication'] | ternary('true', 'false') }}
{% endif %}
{% endif %}

{% if nginx_agent_api is defined and nginx_agent_api is mapping %}
api:
{% if nginx_agent_api['host'] is defined %}
host: {{ nginx_agent_api['host'] }}
{% endif %}
{% if nginx_agent_api['port'] is defined %}
port: {{ nginx_agent_api['port'] }}
{% endif %}
{% if nginx_agent_api['cert'] is defined %}
cert: {{ nginx_agent_api['cert'] }}
{% endif %}
{% if nginx_agent_api['key'] is defined %}
key: {{ nginx_agent_api['key'] }}
{% endif %}
{% endif %}