Add state to manage AuditTrail Logger
PROD-31662
Change-Id: Id1abc4020d984699d28580179463ac31e1c27f64
diff --git a/_states/jenkins_audittrail.py b/_states/jenkins_audittrail.py
new file mode 100644
index 0000000..ced671e
--- /dev/null
+++ b/_states/jenkins_audittrail.py
@@ -0,0 +1,84 @@
+import logging
+
+logger = logging.getLogger(__name__)
+
+def __virtual__():
+ '''
+ Only load if jenkins_common module exist.
+ '''
+ if 'jenkins_common.call_groovy_script' not in __salt__:
+ return (
+ False,
+ 'The jenkins_audittrail state module cannot be loaded: '
+ 'jenkins_common not found')
+ return True
+
+def config (name, type="console", log="", limit=0, count=0, output="STD_OUT",
+ date_format="yyyy-MM-dd HH:mm:ss:SSS", log_prefix="", syslog_server_hostname="",
+ syslog_server_port=514, syslog_facility="SYSLOG",
+ app_name="jenkins", message_hostname="", message_format="RFC_3164"):
+ """
+ Jenkins AuditTrail logging config state method
+
+ :param type: logger type. one of: console (default), file, syslog
+ Console Logger params:
+ :param output: STD_OUT or STD_ERR
+ :param date_format
+ :param log_prefix
+ File Logger params:
+ :param log: path to log file
+ :param limit: log file size
+ :param count: log file count to keep
+ Syslog Logger params:
+ :param syslog_server_hostname
+ :param syslog_server_port
+ :param syslog_facility
+ :param app_name
+ :param message_hostname
+ :param message_format: RFC_3164 or RFC_5424
+
+ :returns: salt-specified state dict
+ """
+
+ template = __salt__['jenkins_common.load_template'](
+ 'salt://jenkins/files/groovy/audittrail_config.template',
+ __env__)
+ return __salt__['jenkins_common.api_call'](name, template,
+ ["CREATED", "EXISTS"],
+ {
+ 'logger_type': type,
+ 'output': output,
+ 'date_format': date_format,
+ 'log_prefix': log_prefix if log_prefix else "",
+ 'log': log if log else "",
+ 'limit': limit,
+ 'count': count,
+ 'syslog_server_hostname': syslog_server_hostname if syslog_server_hostname else "",
+ 'syslog_server_port': syslog_server_port,
+ 'syslog_facility': syslog_facility,
+ 'app_name': app_name,
+ 'message_hostname': message_hostname if message_hostname else "",
+ 'message_format': message_format if message_format else "",
+ },
+ 'AuditTrail logger configuration')
+
+def params (name, pattern="", log_build_cause=True):
+ """
+ Jenkins AuditTrail logging params state method
+
+ :param pattern
+ :param log_build_cause
+
+ :returns: salt-specified state dict
+ """
+
+ template = __salt__['jenkins_common.load_template'](
+ 'salt://jenkins/files/groovy/audittrail_params.template',
+ __env__)
+ return __salt__['jenkins_common.api_call'](name, template,
+ ["CHANGED", "EXISTS"],
+ {
+ 'pattern': pattern if pattern else "",
+ 'log_build_cause': str(log_build_cause).lower(),
+ },
+ 'AuditTrail logger params')
diff --git a/jenkins/client/audittrail.sls b/jenkins/client/audittrail.sls
new file mode 100644
index 0000000..18f9937
--- /dev/null
+++ b/jenkins/client/audittrail.sls
@@ -0,0 +1,27 @@
+{%- from "jenkins/map.jinja" import client with context %}
+{%- if client.audittrail is defined %}
+{%- if client.audittrail.pattern is defined %}
+configure_jenkins_auditrail:
+ jenkins_audittrail.params:
+ - pattern: {{ client.audittrail.pattern }}
+ - log_build_cause: {{ client.audittrail.get('log_build_cause', True) }}
+{%- endif %}
+
+{% for name, logger in client.audittrail.get('loggers', {}).iteritems() %}
+configure_jenkins_logger_{{ name }}:
+ jenkins_audittrail.config:
+ - type: {{ logger.get('type', 'console') }}
+ - output: {{ logger.get('output', 'STD_OUT') }}
+ - date_format: {{ logger.get('date_format', 'yyyy-MM-dd HH:mm:ss:SSS') }}
+ - log_prefix: {{ logger.get('log_prefix', '') }}
+ - log: {{ logger.get('log', '') }}
+ - limit: {{ logger.get('limit', 0) }}
+ - count: {{ logger.get('count', 0) }}
+ - syslog_server_hostname: {{ logger.get('syslog_server_hostname', '') }}
+ - syslog_server_port: {{ logger.get('syslog_server_port', 514) }}
+ - syslog_facility: {{ logger.get('syslog_facility', 'SYSLOG') }}
+ - app_name: {{ logger.get('app_name', 'jenkins') }}
+ - message_hostname: {{ logger.get('message_hostname', '') }}
+ - message_format: {{ logger.get('message_format', 'RFC_3164') }}
+{% endfor %}
+{%- endif %}
\ No newline at end of file
diff --git a/jenkins/client/init.sls b/jenkins/client/init.sls
index 85cacb3..99b2897 100644
--- a/jenkins/client/init.sls
+++ b/jenkins/client/init.sls
@@ -74,6 +74,9 @@
{%- if client.flowdurabilitylevel is defined %}
- jenkins.client.flowdurability
{%- endif %}
+{%- if client.audittrail is defined %}
+ - jenkins.client.audittrail
+{%- endif %}
# execute job enforcements as last
{%- if client.job is defined %}
diff --git a/jenkins/files/groovy/audittrail_config.template b/jenkins/files/groovy/audittrail_config.template
new file mode 100644
index 0000000..9eef4b4
--- /dev/null
+++ b/jenkins/files/groovy/audittrail_config.template
@@ -0,0 +1,66 @@
+#!groovy
+
+import jenkins.model.*
+import hudson.*
+import hudson.plugins.audit_trail.*;
+
+def loggerType = "${logger_type}"
+Jenkins j = Jenkins.getInstance();
+AuditTrailPlugin plugin = j.getPlugin(AuditTrailPlugin.class);
+def entry
+def result
+
+switch (loggerType) {
+ case 'file':
+ result = plugin.loggers.find{
+ it instanceof LogFileAuditLogger &&
+ it.getLog() == "${log}" &&
+ it.getLimit().toString() == "${limit}" &&
+ it.getCount().toString() == "${count}"
+ }
+ entry = new LogFileAuditLogger("${log}", ${limit}, ${count})
+ break
+ case 'syslog':
+ result = plugin.loggers.find{
+ it instanceof SyslogAuditLogger &&
+ it.getSyslogServerHostname() == "${syslog_server_hostname}" &&
+ it.getSyslogServerPort().toString() == "${syslog_server_port}" &&
+ it.getAppName() == "${app_name}" &&
+ it.getMessageHostname() == ("${message_hostname}" ?: null) &&
+ it.getFacility() == "${syslog_facility}" &&
+ it.getMessageFormat() == "${message_format}"
+ }
+ entry = new SyslogAuditLogger("${syslog_server_hostname}", ${syslog_server_port}, "${app_name}",
+ "${message_hostname}", "${syslog_facility}", "${message_format}")
+ break
+ default:
+ result = plugin.loggers.find{
+ it instanceof ConsoleAuditLogger &&
+ it.getOutput().toString() == "${output}" &&
+ it.getDateFormat() == "${date_format}" &&
+ it.getLogPrefix() == "${log_prefix}"
+ }
+ entry = new ConsoleAuditLogger(ConsoleAuditLogger.Output.${output}, "${date_format}", "${log_prefix}")
+ break
+}
+
+if (result) {
+ print("EXISTS")
+} else {
+ switch (loggerType) {
+ case 'file':
+ plugin.loggers.removeAll { it instanceof LogFileAuditLogger && it.getLog() == "${log}" }
+ break
+ case 'syslog':
+ plugin.loggers.removeAll { it instanceof SyslogAuditLogger &&
+ it.getSyslogServerHostname() == "${syslog_server_hostname}" }
+ break
+ default:
+ plugin.loggers.removeAll { it instanceof ConsoleAuditLogger && it.getOutput().toString() == "${output}" }
+ break
+ }
+ plugin.loggers.add(entry)
+ plugin.save()
+ plugin.start()
+ print("CREATED")
+}
diff --git a/jenkins/files/groovy/audittrail_params.template b/jenkins/files/groovy/audittrail_params.template
new file mode 100644
index 0000000..c1b5486
--- /dev/null
+++ b/jenkins/files/groovy/audittrail_params.template
@@ -0,0 +1,25 @@
+#!groovy
+
+import jenkins.model.*
+import hudson.*
+import hudson.plugins.audit_trail.AuditTrailPlugin;
+
+Jenkins j = Jenkins.getInstance();
+AuditTrailPlugin plugin = j.getPlugin(AuditTrailPlugin.class);
+def result = 'EXISTS'
+
+if (plugin.getLogBuildCause() != "${log_build_cause}".toBoolean()) {
+ result = 'CHANGED'
+ plugin.logBuildCause = "${log_build_cause}".toBoolean()
+}
+if (plugin.getPattern() != "${pattern}") {
+ result = 'CHANGED'
+ plugin.pattern = "${pattern}"
+}
+
+if (result == 'CHANGED') {
+ plugin.save()
+ plugin.start()
+}
+
+print(result)
diff --git a/jenkins/schemas/client.yaml b/jenkins/schemas/client.yaml
index 8373397..0e5355b 100644
--- a/jenkins/schemas/client.yaml
+++ b/jenkins/schemas/client.yaml
@@ -523,6 +523,50 @@
type: string
color:
type: string
+ audittrail:
+ description: Jenkins configuration of Audit Trail plugin
+ type: object
+ additionalProperties: false
+ properties:
+ pattern:
+ type: string
+ log_build_cause:
+ type: boolean
+ loggers:
+ type: object
+ additionalProperties: false
+ patternProperties:
+ "^[A-Za-z0-9_\\-]*$":
+ type: object
+ additionalProperties: false
+ properties:
+ type:
+ type: string
+ output:
+ type: string
+ enum: ['STD_OUT', 'STD_ERR']
+ date_format:
+ type: string
+ log_prefix:
+ type: string
+ log:
+ type: string
+ limit:
+ type: integer
+ count:
+ type: integer
+ syslog_server_hostname:
+ type: string
+ syslog_server_port:
+ type: integer
+ syslog_facility:
+ type: string
+ app_name:
+ type: string
+ message_hostname:
+ type: string
+ message_format:
+ type: string
job:
description: Jenkins jobs configuration
type: object
diff --git a/tests/pillar/client.sls b/tests/pillar/client.sls
index 21f5ed2..42c9d91 100644
--- a/tests/pillar/client.sls
+++ b/tests/pillar/client.sls
@@ -1,6 +1,22 @@
jenkins:
client:
enabled: true
+ audittrail:
+ pattern: '.*'
+ loggers:
+ log_to_file:
+ type: file
+ log: "/var/log/jenkins_audit.log"
+ limit: 100
+ count: 10
+ log_to_syslog:
+ type: syslog
+ syslog_server_hostname: example.syslog.com
+ syslog_facility: LOCAL0
+ message_hostname: example.jenkins.com
+ log_to_console:
+ output: STD_OUT
+ date_format: "yyyy-MM-dd HH:mm:ss:SSS"
flowdurabilitylevel: PERFORMANCE_OPTIMIZED
master:
host: jenkins.example.com