Merge pull request #998 from fraenki/zabbix_140

net-mgmt/zabbix-agent: release 1.4
This commit is contained in:
Frank Wall
2018-11-19 15:16:29 +01:00
committed by GitHub
9 changed files with 334 additions and 264 deletions
+1 -2
View File
@@ -1,6 +1,5 @@
PLUGIN_NAME= zabbix-agent
PLUGIN_VERSION= 1.3
PLUGIN_REVISION= 1
PLUGIN_VERSION= 1.4
PLUGIN_COMMENT= Enterprise-class open source distributed monitoring agent
PLUGIN_DEPENDS= zabbix34-agent
PLUGIN_MAINTAINER= opnsense@moov.de
@@ -42,4 +42,66 @@ class SettingsController extends ApiMutableModelControllerBase
{
static protected $internalModelName = 'zabbixagent';
static protected $internalModelClass = '\OPNsense\ZabbixAgent\ZabbixAgent';
public function searchUserparametersAction()
{
return $this->searchBase('userparameters.userparameter', array("enabled", "key", "command"));
}
public function getUserparameterAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('userparameter', 'userparameters.userparameter', $uuid);
}
public function addUserparameterAction()
{
return $this->addBase('userparameter', 'userparameters.userparameter');
}
public function delUserparameterAction($uuid)
{
return $this->delBase('userparameters.userparameter', $uuid);
}
public function setUserparameterAction($uuid)
{
return $this->setBase('userparameter', 'userparameters.userparameter', $uuid);
}
public function toggleUserparameterAction($uuid)
{
return $this->toggleBase('userparameters.userparameter', $uuid);
}
public function searchAliasesAction()
{
return $this->searchBase('aliases.alias', array("enabled", "key", "sourceKey"));
}
public function getAliasAction($uuid = null)
{
$this->sessionClose();
return $this->getBase('alias', 'aliases.alias', $uuid);
}
public function addAliasAction()
{
return $this->addBase('alias', 'aliases.alias');
}
public function delAliasAction($uuid)
{
return $this->delBase('aliases.alias', $uuid);
}
public function setAliasAction($uuid)
{
return $this->setBase('alias', 'aliases.alias', $uuid);
}
public function toggleAliasAction($uuid)
{
return $this->toggleBase('aliases.alias', $uuid);
}
}
@@ -43,6 +43,10 @@ class IndexController extends \OPNsense\Base\IndexController
{
// include form definitions
$this->view->settingsForm = $this->getForm("settings");
// link userparameter dialog
$this->view->formDialogUserparameter = $this->getForm("dialogUserparameter");
// link alias dialog
$this->view->formDialogAlias = $this->getForm("dialogAlias");
// pick the template to serve
$this->view->pick('OPNsense/ZabbixAgent/index');
}
@@ -0,0 +1,26 @@
<form>
<field>
<id>alias.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help>Enable this alias.</help>
</field>
<field>
<id>alias.key</id>
<label>Alias Item Key</label>
<type>text</type>
<help>Enter a unique item key of your choice.</help>
</field>
<field>
<id>alias.sourceKey</id>
<label>Source Item Key</label>
<type>text</type>
<help>Enter the name of an existing item key.</help>
</field>
<field>
<id>alias.acceptParams</id>
<label>Accept Parameters</label>
<type>checkbox</type>
<help>Enable to accept parameters for this alias.</help>
</field>
</form>
@@ -0,0 +1,26 @@
<form>
<field>
<id>userparameter.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help>Enable this userparameter.</help>
</field>
<field>
<id>userparameter.key</id>
<label>Key</label>
<type>text</type>
<help>Enter a unique item key of your choice.</help>
</field>
<field>
<id>userparameter.command</id>
<label>Command</label>
<type>text</type>
<help>Command to be executed to evaluate value of the key.</help>
</field>
<field>
<id>userparameter.acceptParams</id>
<label>Accept Parameters</label>
<type>checkbox</type>
<help>Flexible user parameters accept parameters with the key. This way a flexible user parameter can be the basis for creating several items.</help>
</field>
</form>
@@ -1,4 +1,5 @@
<form>
<activetab>zabbixagent-settings-main</activetab>
<tab id="zabbixagent-settings-main" description="Main Settings">
<field>
<id>zabbixagent.settings.main.enabled</id>
@@ -125,5 +126,4 @@
<help><![CDATA[Enable logging of executed shell commands as warnings. Make sure to set the Debug Level accordingly.]]></help>
</field>
</tab>
<activetab>zabbixagent-settings-main</activetab>
</form>
@@ -1,9 +1,7 @@
<model>
<mount>//OPNsense/ZabbixAgent</mount>
<version>1.1.0</version>
<description>
Enterprise-class open source distributed monitoring agent
</description>
<version>1.2.0</version>
<description>Enterprise-class open source distributed monitoring agent</description>
<items>
<!-- local settings that should NOT be synced to another node -->
<local>
@@ -132,5 +130,55 @@
</logRemoteCommands>
</features>
</settings>
<userparameters>
<userparameter type="ArrayField">
<id type="UniqueIdField">
<Required>Y</Required>
</id>
<enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</enabled>
<key type="TextField">
<mask>/^[^\t^,^;^\.^\[^\]^\{^\}]{1,255}$/u</mask>
<ValidationMessage>Should be a string between 1 and 255 characters.</ValidationMessage>
<Required>Y</Required>
</key>
<command type="TextField">
<mask>/^[^\t^,^;^\.^\[^\]^\{^\}]{1,4096}$/u</mask>
<ValidationMessage>Should be a string between 1 and 4096 characters.</ValidationMessage>
<Required>Y</Required>
</command>
<acceptParams type="BooleanField">
<default>0</default>
<Required>Y</Required>
</acceptParams>
</userparameter>
</userparameters>
<aliases>
<alias type="ArrayField">
<id type="UniqueIdField">
<Required>Y</Required>
</id>
<enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</enabled>
<key type="TextField">
<mask>/^[^\t^,^;^\.^\[^\]^\{^\}]{1,255}$/u</mask>
<ValidationMessage>Should be a string between 1 and 255 characters.</ValidationMessage>
<Required>Y</Required>
</key>
<sourceKey type="TextField">
<mask>/^[^\t]{1,4096}$/u</mask>
<ValidationMessage>Should be a string between 1 and 4096 characters.</ValidationMessage>
<Required>Y</Required>
</sourceKey>
<acceptParams type="BooleanField">
<default>0</default>
<Required>Y</Required>
</acceptParams>
</alias>
</aliases>
</items>
</model>
@@ -36,6 +36,36 @@ $( document ).ready(function() {
updateServiceControlUI('zabbixagent');
});
/***********************************************************************
* link grid actions
**********************************************************************/
$("#grid-userparameters").UIBootgrid(
{ search:'/api/zabbixagent/settings/searchUserparameters',
get:'/api/zabbixagent/settings/getUserparameter/',
set:'/api/zabbixagent/settings/setUserparameter/',
add:'/api/zabbixagent/settings/addUserparameter/',
del:'/api/zabbixagent/settings/delUserparameter/',
toggle:'/api/zabbixagent/settings/toggleUserparameter/',
options: {
rowCount:[10,25,50,100,500,1000]
}
}
);
$("#grid-aliases").UIBootgrid(
{ search:'/api/zabbixagent/settings/searchAliases',
get:'/api/zabbixagent/settings/getAlias/',
set:'/api/zabbixagent/settings/setAlias/',
add:'/api/zabbixagent/settings/addAlias/',
del:'/api/zabbixagent/settings/delAlias/',
toggle:'/api/zabbixagent/settings/toggleAlias/',
options: {
rowCount:[10,25,50,100,500,1000]
}
}
);
/***********************************************************************
* Commands
**********************************************************************/
@@ -45,6 +75,7 @@ $( document ).ready(function() {
$(this).click(function(){
var frm_id = $(this).closest("form").attr("id");
var frm_title = $(this).closest("form").attr("data-title");
// save data for tab
saveFormToEndpoint(url="/api/zabbixagent/settings/set",formid=frm_id,callback_ok=function(){
// set progress animation when reloading
@@ -66,6 +97,33 @@ $( document ).ready(function() {
} else {
updateServiceControlUI('zabbixagent');
}
// when done, disable progress animation.
$("#"+frm_id+"_progress").removeClass("fa fa-spinner fa-pulse");
});
});
});
});
// Reconfigure - activate changes
$('[id*="reconfigureAct"]').each(function(){
$(this).click(function(){
// set progress animation
$('[id*="reconfigureAct_progress"]').each(function(){
$(this).addClass("fa fa-spinner fa-pulse");
});
// reconfigure service
ajaxCall(url="/api/zabbixagent/service/reconfigure", sendData={}, callback=function(data,status) {
if (status != "success" || data['status'] != 'ok') {
BootstrapDialog.show({
type: BootstrapDialog.TYPE_WARNING,
title: "{{ lang._('Error reconfiguring Zabbix Agent') }}",
message: data['status'],
draggable: true
});
}
// when done, disable progress animation
$('[id*="reconfigureAct_progress"]').each(function(){
$(this).removeClass("fa fa-spinner fa-pulse");
});
});
});
@@ -83,8 +141,91 @@ $( document ).ready(function() {
<ul class="nav nav-tabs" role="tablist" id="maintabs">
{{ partial("layout_partials/base_tabs_header",['formData':settingsForm]) }}
{# manually add tab menu #}
<li role="presentation" class="dropdown">
<a data-toggle="dropdown" href="#" class="dropdown-toggle pull-right visible-lg-inline-block visible-md-inline-block visible-xs-inline-block visible-sm-inline-block" role="button">
<b><span class="caret"></span></b>
</a>
<a data-toggle="tab" onclick="$('#userparameters-tab').click();" class="visible-lg-inline-block visible-md-inline-block visible-xs-inline-block visible-sm-inline-block" style="border-right:0px;"><b>{{ lang._('Advanced') }}</b></a>
<ul class="dropdown-menu" role="menu">
<li><a data-toggle="tab" id="userparameters-tab" href="#userparameters">{{ lang._('User Parameters') }}</a></li>
<li><a data-toggle="tab" id="aliases-tab" href="#aliases">{{ lang._('Item Key Aliases') }}</a></li>
</ul>
</li>
</ul>
<div class="content-box tab-content">
{# add automatically generated tab content #}
{{ partial("layout_partials/base_tabs_content",['formData':settingsForm]) }}
{# manually add tab content #}
<div id="userparameters" class="tab-pane fade">
<!-- tab page "userparameters" -->
<table id="grid-userparameters" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="DialogUserparameter">
<thead>
<tr>
<th data-column-id="enabled" data-width="6em" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="key" data-type="string">{{ lang._('User Parameter Key') }}</th>
<th data-column-id="command" data-type="string">{{ lang._('User Parameter Command') }}</th>
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
</table>
<!-- apply button -->
<div class="col-md-12">
<hr/>
<button class="btn btn-primary" id="reconfigureAct-userparameters" type="button"><b>{{ lang._('Apply') }}</b><i id="reconfigureAct_progress" class=""></i></button>
<br/>
<br/>
</div>
</div>
<div id="aliases" class="tab-pane fade">
<!-- tab page "aliases" -->
<table id="grid-aliases" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="DialogAlias">
<thead>
<tr>
<th data-column-id="enabled" data-width="6em" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="key" data-type="string">{{ lang._('Alias Key') }}</th>
<th data-column-id="sourceKey" data-type="string">{{ lang._('Alias Source Key') }}</th>
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
</table>
<!-- apply button -->
<div class="col-md-12">
<hr/>
<button class="btn btn-primary" id="reconfigureAct-aliases" type="button"><b>{{ lang._('Apply') }}</b><i id="reconfigureAct_progress" class=""></i></button>
<br/>
<br/>
</div>
</div>
</div>
{# include dialogs #}
{{ partial("layout_partials/base_dialog",['fields':formDialogUserparameter,'id':'DialogUserparameter','label':lang._('Edit User Parameter')]) }}
{{ partial("layout_partials/base_dialog",['fields':formDialogAlias,'id':'DialogAlias','label':lang._('Edit Alias')]) }}
@@ -4,305 +4,69 @@
{% if helpers.exists('OPNsense.ZabbixAgent.settings') %}
# This is a config file for zabbix agent (unix)
# to get more information about zabbix, visit http://www.zabbix.com
############ GENERAL PARAMETERS #################
### Option: PidFile
# Name of PID file.
#
PidFile=/var/run/zabbix/zabbix_agentd.pid
### Option: LogType
# Specifies where log messages are written to:
# system - syslog
# file - file specified with LogFile parameter
# console - standard output
#
LogType=file
### Option: LogFile
# Log file name for LogType 'file' parameter.
#
LogFile=/var/log/zabbix/zabbix_agentd.log
### Option: LogFileSize
# Maximum size of log file in MB.
# 0 - disable automatic log rotation.
#
LogFileSize={{OPNsense.ZabbixAgent.settings.main.logFileSize}}
### Option: DebugLevel
# Specifies debug level
# 0 - basic information about starting and stopping of Zabbix processes
# 1 - critical information
# 2 - error information
# 3 - warnings
# 4 - for debugging (produces lots of information)
# 5 - extended debugging (produces even more information)
DebugLevel={{OPNsense.ZabbixAgent.settings.main.debugLevel|replace("val_", "")}}
### Option: SourceIP
# Source IP address for outgoing connections.
#
{% if helpers.exists('OPNsense.ZabbixAgent.settings.main.sourceIP') %}
SourceIP={{OPNsense.ZabbixAgent.settings.main.sourceIP}}
{% endif %}
### Option: EnableRemoteCommands
# Whether remote commands from Zabbix server are allowed.
# 0 - not allowed
# 1 - allowed
#
EnableRemoteCommands={{OPNsense.ZabbixAgent.settings.features.enableRemoteCommands}}
### Option: LogRemoteCommands
# Enable logging of executed shell commands as warnings.
# 0 - disabled
# 1 - enabled
#
LogRemoteCommands={{OPNsense.ZabbixAgent.settings.features.logRemoteCommands}}
##### Passive checks related
### Option: Server
# List of comma delimited IP addresses (or hostnames) of Zabbix servers.
# Incoming connections will be accepted only from the hosts listed here.
# If IPv6 support is enabled then '127.0.0.1', '::127.0.0.1', '::ffff:127.0.0.1' are treated equally.
#
Server={{OPNsense.ZabbixAgent.settings.main.serverList}}
### Option: ListenPort
# Agent will listen on this port for connections from the server.
#
ListenPort={{OPNsense.ZabbixAgent.settings.main.listenPort}}
### Option: ListenIP
# List of comma delimited IP addresses that the agent should listen on.
# First IP address is sent to Zabbix server if connecting to it to retrieve list of active checks.
#
ListenIP={{OPNsense.ZabbixAgent.settings.main.listenIP}}
### Option: StartAgents
# Number of pre-forked instances of zabbix_agentd that process passive checks.
# If set to 0, disables passive checks and the agent will not listen on any TCP port.
#
StartAgents={{OPNsense.ZabbixAgent.settings.tuning.startAgents}}
##### Active checks related
### Option: ServerActive
# List of comma delimited IP:port (or hostname:port) pairs of Zabbix servers for active checks.
# If port is not specified, default port is used.
# IPv6 addresses must be enclosed in square brackets if port for that host is specified.
# If port is not specified, square brackets for IPv6 addresses are optional.
# If this parameter is not specified, active checks are disabled.
# Example: ServerActive=127.0.0.1:20051,zabbix.domain,[::1]:30051,::1,[12fc::1]
#
{% if OPNsense.ZabbixAgent.settings.features.enableActiveChecks == '1' and OPNsense.ZabbixAgent.settings.features.activeCheckServers|default("") != "" %}
ServerActive={{OPNsense.ZabbixAgent.settings.features.activeCheckServers}}
{% endif %}
### Option: Hostname
# Unique, case sensitive hostname.
# Required for active checks and must match hostname as configured on the server.
# Value is acquired from HostnameItem if undefined.
#
{% if OPNsense.ZabbixAgent.local.hostname|default("") != "" %}
Hostname={{OPNsense.ZabbixAgent.local.hostname}}
{% endif %}
### Option: HostnameItem
# Item used for generating Hostname if it is undefined. Ignored if Hostname is defined.
# Does not support UserParameters or aliases.
#
### Option: HostMetadata
# Optional parameter that defines host metadata.
# Host metadata is used at host auto-registration process.
# An agent will issue an error and not start if the value is over limit of 255 characters.
# If not defined, value will be acquired from HostMetadataItem.
#
### Option: HostMetadataItem
# Optional parameter that defines an item used for getting host metadata.
# Host metadata is used at host auto-registration process.
# During an auto-registration request an agent will log a warning message if
# the value returned by specified item is over limit of 255 characters.
# This option is only used when HostMetadata is not defined.
#
### Option: RefreshActiveChecks
# How often list of active checks is refreshed, in seconds.
#
StartAgents={{OPNsense.ZabbixAgent.settings.tuning.startAgents}}
RefreshActiveChecks={{OPNsense.ZabbixAgent.settings.features.refreshActiveChecks}}
### Option: BufferSend
# Do not keep data longer than N seconds in buffer.
#
BufferSend={{OPNsense.ZabbixAgent.settings.tuning.bufferSend}}
### Option: BufferSize
# Maximum number of values in a memory buffer. The agent will send
# all collected data to Zabbix Server or Proxy if the buffer is full.
#
BufferSize={{OPNsense.ZabbixAgent.settings.tuning.bufferSize}}
### Option: MaxLinesPerSecond
# Maximum number of new lines the agent will send per second to Zabbix Server
# or Proxy processing 'log' and 'logrt' active checks.
# The provided value will be overridden by the parameter 'maxlines',
# provided in 'log' or 'logrt' item keys.
#
MaxLinesPerSecond={{OPNsense.ZabbixAgent.settings.tuning.maxLinesPerSecond}}
############ ADVANCED PARAMETERS #################
### Option: Alias
# Sets an alias for an item key. It can be used to substitute long and complex item key with a smaller and simpler one.
# Multiple Alias parameters may be present. Multiple parameters with the same Alias key are not allowed.
# Different Alias keys may reference the same item key.
# For example, to retrieve the ID of user 'zabbix':
# Alias=zabbix.userid:vfs.file.regexp[/etc/passwd,^zabbix:.:([0-9]+),,,,\1]
# Now shorthand key zabbix.userid may be used to retrieve data.
# Aliases can be used in HostMetadataItem but not in HostnameItem parameters.
#
{% if helpers.exists('OPNsense.ZabbixAgent.aliases') %}
{% for alias in helpers.toList('OPNsense.ZabbixAgent.aliases.alias') %}
{% if alias.enabled == '1' %}
{% if alias.acceptParams == '1' %}
{% set alias_opts = '[*]' %}
{% endif %}
Alias={{alias.key}}{{alias_opts}}:{{alias.sourceKey}}
{% endif %}
{% endfor %}
{% endif %}
### Option: Timeout
# Spend no more than Timeout seconds on processing
#
Timeout={{OPNsense.ZabbixAgent.settings.tuning.timeout}}
### Option: AllowRoot
# Allow the agent to run as 'root'. If disabled and the agent is started by 'root', the agent
# will try to switch to the user specified by the User configuration option instead.
# Has no effect if started under a regular user.
# 0 - do not allow
# 1 - allow
#
AllowRoot=0
### Option: User
# Drop privileges to a specific, existing user on the system.
# Only has effect if run as 'root' and AllowRoot is disabled.
#
User=zabbix
### Option: Include
# You may include individual files or all files in a directory in the configuration file.
# Installing Zabbix will create include directory in /usr/local/etc, unless modified during the compile time.
#
Include=/usr/local/etc/zabbix_agentd.conf.d
####### USER-DEFINED MONITORED PARAMETERS #######
### Option: UnsafeUserParameters
# Allow all characters to be passed in arguments to user-defined parameters.
# The following characters are not allowed:
# \ ' " ` * ? [ ] { } ~ $ ! & ; ( ) < > | # @
# Additionally, newline characters are not allowed.
# 0 - do not allow
# 1 - allow
#
### Option: UserParameter
# User-defined parameter to monitor. There can be several user-defined parameters.
# Format: UserParameter=<key>,<shell command>
# See 'zabbix_agentd' directory for examples.
#
# Disabled. A configuration file should be placed on directory: <%= @include %>
####### LOADABLE MODULES #######
### Option: LoadModulePath
# Full path to location of agent modules.
# Default depends on compilation options.
#
#LoadModulePath=/usr/local/lib/modules
### Option: LoadModule
# Module to load at agent startup. Modules are used to extend functionality of the agent.
# Format: LoadModule=<module.so>
# The modules must be located in directory specified by LoadModulePath.
# It is allowed to include multiple LoadModule parameters.
#
####### TLS-RELATED PARAMETERS #######
### Option: TLSConnect
# How the proxy should connect to Zabbix server. Used for an active proxy, ignored on a passive proxy.
# Only one value can be specified:
# unencrypted - connect without encryption
# psk - connect using TLS and a pre-shared key
# cert - connect using TLS and a certificate
#
# Mandatory: yes, if TLS certificate or PSK parameters are defined (even for 'unencrypted' connection)
# Default:
# TLSConnect=unencrypted
### Option: TLSAccept
# What incoming connections to accept from Zabbix server. Used for a passive proxy, ignored on an active proxy.
# Multiple values can be specified, separated by comma:
# unencrypted - accept connections without encryption
# psk - accept connections secured with TLS and a pre-shared key
# cert - accept connections secured with TLS and a certificate
#
# Mandatory: yes, if TLS certificate or PSK parameters are defined (even for 'unencrypted' connection)
# Default:
# TLSAccept=unencrypted
### Option: TLSCAFile
# Full pathname of a file containing the top-level CA(s) certificates for
# peer certificate verification.
#
# Mandatory: no
# Default:
# TLSCAFile=
### Option: TLSCRLFile
# Full pathname of a file containing revoked certificates.
#
# Mandatory: no
# Default:
# TLSCRLFile=
### Option: TLSServerCertIssuer
# Allowed server certificate issuer.
#
# Mandatory: no
# Default:
# TLSServerCertIssuer=
### Option: TLSServerCertSubject
# Allowed server certificate subject.
#
# Mandatory: no
# Default:
# TLSServerCertSubject=
### Option: TLSCertFile
# Full pathname of a file containing the proxy certificate or certificate chain.
#
# Mandatory: no
# Default:
# TLSCertFile=
### Option: TLSKeyFile
# Full pathname of a file containing the proxy private key.
#
# Mandatory: no
# Default:
# TLSKeyFile=
### Option: TLSPSKIdentity
# Unique, case sensitive string used to identify the pre-shared key.
#
# Mandatory: no
# Default:
# TLSPSKIdentity=
### Option: TLSPSKFile
# Full pathname of a file containing the pre-shared key.
#
# Mandatory: no
# Default:
# TLSPSKFile=
{% if helpers.exists('OPNsense.ZabbixAgent.userparameters') %}
{% for userparam in helpers.toList('OPNsense.ZabbixAgent.userparameters.userparameter') %}
{% if userparam.enabled == '1' %}
{% if userparam.acceptParams == '1' %}
{% set userparam_opts = '[*]' %}
{% endif %}
UserParameter={{userparam.key}}{{userparam_opts}},{{userparam.command}}
{% endif %}
{% endfor %}
{% endif %}
{% endif %}