mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 08:58:59 +00:00
Merge pull request #15392 from ihrwein/f/add-syslog-ng-modules
F/add syslog ng modules
This commit is contained in:
commit
d6e3e01c6d
@ -218,6 +218,7 @@ Full list of builtin execution modules
|
||||
svn
|
||||
swift
|
||||
sysbench
|
||||
syslog_ng
|
||||
sysmod
|
||||
system
|
||||
systemd
|
||||
|
6
doc/ref/modules/all/salt.modules.syslog_ng.rst
Normal file
6
doc/ref/modules/all/salt.modules.syslog_ng.rst
Normal file
@ -0,0 +1,6 @@
|
||||
======================
|
||||
salt.modules.syslog_ng
|
||||
======================
|
||||
|
||||
.. automodule:: salt.modules.syslog_ng
|
||||
:members:
|
@ -123,6 +123,7 @@ Full list of builtin state modules
|
||||
supervisord
|
||||
svn
|
||||
sysctl
|
||||
syslog_ng
|
||||
test
|
||||
timezone
|
||||
tomcat
|
||||
|
6
doc/ref/states/all/salt.states.syslog_ng.rst
Normal file
6
doc/ref/states/all/salt.states.syslog_ng.rst
Normal file
@ -0,0 +1,6 @@
|
||||
=====================
|
||||
salt.states.syslog_ng
|
||||
=====================
|
||||
|
||||
.. automodule:: salt.states.syslog_ng
|
||||
:members:
|
@ -3,7 +3,10 @@
|
||||
Syslog-ng usage
|
||||
===============
|
||||
|
||||
The syslog\_ng state modul is to generate syslog-ng
|
||||
Overview
|
||||
--------
|
||||
|
||||
Syslog\_ng state module is for generating syslog-ng
|
||||
configurations. You can do the following things:
|
||||
|
||||
- generate syslog-ng configuration from YAML,
|
||||
@ -16,130 +19,199 @@ configuration, get the version and other information about syslog-ng.
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
The following configuration is an example, how a complete syslog-ng
|
||||
state configuration looks like:
|
||||
Users can create syslog-ng configuration statements with the
|
||||
:py:func:`syslog_ng.config <salt.states.syslog_ng.config>` function. It requires
|
||||
a `name` and a `config` parameter. The `name` parameter determines the name of
|
||||
the generated statement and the `config` parameter holds a parsed YAML structure.
|
||||
|
||||
A statement can be declared in the following forms (both are equivalent):
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
source.s_localhost:
|
||||
syslog_ng.config:
|
||||
- config:
|
||||
- tcp:
|
||||
- ip: "127.0.0.1"
|
||||
- port: 1233
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
s_localhost:
|
||||
syslog_ng.config:
|
||||
- config:
|
||||
source:
|
||||
- tcp:
|
||||
- ip: "127.0.0.1"
|
||||
- port: 1233
|
||||
|
||||
The first one is called short form, because it needs less typing. Users can use lists
|
||||
and dictionaries to specify their configuration. The format is quite self describing and
|
||||
there are more examples [at the end](#examples) of this document.
|
||||
|
||||
Quotation
|
||||
---------
|
||||
The quotation can be tricky sometimes but here are some rules to follow:
|
||||
* when a string meant to be ``"string"`` in the generated configuration, it should be like
|
||||
``'"string"'`` in the YAML document
|
||||
* similarly, users should write ``"'string'"`` to get ``'string'`` in the generated configuration
|
||||
|
||||
Full example
|
||||
------------
|
||||
|
||||
The following configuration is an example, how a complete syslog-ng configuration looks like:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# Set the location of the configuration file
|
||||
"/home/tibi/install/syslog-ng/etc/syslog-ng.conf":
|
||||
syslog_ng.set_config_file
|
||||
set_location:
|
||||
module.run:
|
||||
- name: syslog_ng.set_config_file
|
||||
- m_name: "/home/tibi/install/syslog-ng/etc/syslog-ng.conf"
|
||||
|
||||
# The syslog-ng and syslog-ng-ctl binaries are here. You needn't use
|
||||
# The syslog-ng and syslog-ng-ctl binaries are here. You needn't use
|
||||
# this method if these binaries can be found in a directory in your PATH.
|
||||
"/home/tibi/install/syslog-ng/sbin":
|
||||
syslog_ng.set_binary_path
|
||||
set_bin_path:
|
||||
module.run:
|
||||
- name: syslog_ng.set_binary_path
|
||||
- m_name: "/home/tibi/install/syslog-ng/sbin"
|
||||
|
||||
# Writes the first lines into the config file, also erases its previous
|
||||
# content
|
||||
"3.6":
|
||||
syslog_ng.write_version
|
||||
write_version:
|
||||
module.run:
|
||||
- name: syslog_ng.write_version
|
||||
- m_name: "3.6"
|
||||
|
||||
# There is a shorter form to set the above variables
|
||||
set_variables:
|
||||
module.run:
|
||||
- name: syslog_ng.set_parameters
|
||||
- version: "3.6"
|
||||
- binary_path: "/home/tibi/install/syslog-ng/sbin"
|
||||
- config_file: "/home/tibi/install/syslog-ng/etc/syslog-ng.conf"
|
||||
|
||||
|
||||
# Some global options
|
||||
global_options:
|
||||
options.global_options:
|
||||
syslog_ng.config:
|
||||
- config:
|
||||
options:
|
||||
- time_reap: 30
|
||||
- mark_freq: 10
|
||||
- keep_hostname: "yes"
|
||||
- time_reap: 30
|
||||
- mark_freq: 10
|
||||
- keep_hostname: "yes"
|
||||
|
||||
s_localhost:
|
||||
source.s_localhost:
|
||||
syslog_ng.config:
|
||||
- config:
|
||||
source:
|
||||
- tcp:
|
||||
- ip: "127.0.0.1"
|
||||
- port: 1233
|
||||
- tcp:
|
||||
- ip: "127.0.0.1"
|
||||
- port: 1233
|
||||
|
||||
d_log_server:
|
||||
destination.d_log_server:
|
||||
syslog_ng.config:
|
||||
- config:
|
||||
destination:
|
||||
- tcp:
|
||||
- "127.0.0.1"
|
||||
- port: 1234
|
||||
- tcp:
|
||||
- "127.0.0.1"
|
||||
- port: 1234
|
||||
|
||||
l_log_to_central_server:
|
||||
log.l_log_to_central_server:
|
||||
syslog_ng.config:
|
||||
- config:
|
||||
log:
|
||||
- source: s_localhost
|
||||
- destination: d_log_server
|
||||
- source: s_localhost
|
||||
- destination: d_log_server
|
||||
|
||||
some_comment:
|
||||
syslog_ng.write_config:
|
||||
module.run:
|
||||
- name: syslog_ng.write_config
|
||||
- config: |
|
||||
# Multi line
|
||||
# comment
|
||||
|
||||
auto_start_or_reload:
|
||||
{% set pids = salt["ps.pgrep"]("syslog-ng") %}
|
||||
{% if pids == None or pids|length == 0 %}
|
||||
syslog_ng.started:
|
||||
- user: tibi
|
||||
{% else %}
|
||||
syslog_ng.reloaded
|
||||
{% endif %}
|
||||
# An other mode to use comments or existing configuration snippets
|
||||
config.other_comment_form:
|
||||
syslog_ng.config:
|
||||
- config: |
|
||||
# Multi line
|
||||
# comment
|
||||
|
||||
#auto_stop:
|
||||
# syslog_ng.stopped
|
||||
|
||||
The ``3.6``, ``s_devlog``, ``d_log_server``, etc. are identifiers. The
|
||||
second lines in each block are functions and their first parameter is
|
||||
their id. The ``- config`` is the second named parameter of the
|
||||
``syslog_ng.config`` function. This function can generate the syslog-ng
|
||||
configuration from YAML. If the statement (source, destination, parser,
|
||||
|
||||
The :py:func:`syslog_ng.reloaded <salt.states.syslog_ng.reloaded>` function can generate syslog-ng configuration from YAML. If the statement (source, destination, parser,
|
||||
etc.) has a name, this function uses the id as the name, otherwise (log
|
||||
statement) it's purpose is like a mandatory comment.
|
||||
|
||||
You can use ``set_binary_path`` to set the directory which contains the
|
||||
syslog-ng and syslog-ng-ctl binaries. If this directory is in your PATH,
|
||||
you don't need to use this function.
|
||||
|
||||
Under ``auto_start_or_reload`` you can see a Jinja template. If
|
||||
syslog-ng isn't running it will start it, otherwise reload it. It uses
|
||||
the process name ``syslog-ng`` to determine its running state. I suggest
|
||||
that you use ``service`` state if it's available on your system.
|
||||
|
||||
After execution this example the syslog\_ng state will generate this
|
||||
file:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
#Generated by Salt on 2014-06-19 16:53:11
|
||||
@version: 3.6
|
||||
#Generated by Salt on 2014-08-18 00:11:11
|
||||
@version: 3.6
|
||||
|
||||
options {
|
||||
time_reap(30);
|
||||
mark_freq(10);
|
||||
keep_hostname(yes);
|
||||
};
|
||||
options {
|
||||
time_reap(
|
||||
30
|
||||
);
|
||||
mark_freq(
|
||||
10
|
||||
);
|
||||
keep_hostname(
|
||||
yes
|
||||
);
|
||||
};
|
||||
|
||||
source s_localhost {
|
||||
tcp(
|
||||
ip("127.0.0.1"),
|
||||
port(1233)
|
||||
);
|
||||
};
|
||||
|
||||
destination d_log_server {
|
||||
tcp(
|
||||
"127.0.0.1",
|
||||
port(1234)
|
||||
);
|
||||
};
|
||||
source s_localhost {
|
||||
tcp(
|
||||
ip(
|
||||
127.0.0.1
|
||||
),
|
||||
port(
|
||||
1233
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
log {
|
||||
source(s_localhost);
|
||||
destination(d_log_server);
|
||||
};
|
||||
|
||||
# Multi line
|
||||
# comment
|
||||
destination d_log_server {
|
||||
tcp(
|
||||
127.0.0.1,
|
||||
port(
|
||||
1234
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
log {
|
||||
source(
|
||||
s_localhost
|
||||
);
|
||||
destination(
|
||||
d_log_server
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
# Multi line
|
||||
# comment
|
||||
|
||||
|
||||
# Multi line
|
||||
# comment
|
||||
|
||||
|
||||
Users can include arbitrary texts in the generated configuration with
|
||||
using the ``write_config`` function.
|
||||
using the ``config`` statement (see the example above).
|
||||
|
||||
Syslog_ng module functions
|
||||
--------------------------
|
||||
|
||||
You can use :py:func:`syslog_ng.set_binary_path <salt.modules.syslog_ng.set_binary_path>`
|
||||
to set the directory which contains the
|
||||
syslog-ng and syslog-ng-ctl binaries. If this directory is in your PATH,
|
||||
you don't need to use this function. There is also a :py:func:`syslog_ng.set_config_file <salt.modules.syslog_ng.set_config_file>`
|
||||
function to set the location of the configuration file.
|
||||
|
||||
Examples
|
||||
--------
|
||||
@ -165,7 +237,7 @@ Simple source
|
||||
- config:
|
||||
source:
|
||||
- file:
|
||||
- file: "/var/log/apache/access.log"
|
||||
- file: ''"/var/log/apache/access.log"''
|
||||
- follow_freq : 1
|
||||
- flags:
|
||||
- no-parse
|
||||
@ -180,12 +252,26 @@ OR
|
||||
- config:
|
||||
source:
|
||||
- file:
|
||||
- "/var/log/apache/access.log"
|
||||
- ''"/var/log/apache/access.log"''
|
||||
- follow_freq : 1
|
||||
- flags:
|
||||
- no-parse
|
||||
- validate-utf8
|
||||
|
||||
OR
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
source.s_tail:
|
||||
syslog_ng.config:
|
||||
- config:
|
||||
- file:
|
||||
- ''"/var/log/apache/access.log"''
|
||||
- follow_freq : 1
|
||||
- flags:
|
||||
- no-parse
|
||||
- validate-utf8
|
||||
|
||||
Complex source
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
@ -228,7 +314,7 @@ Filter
|
||||
- config:
|
||||
filter:
|
||||
- match:
|
||||
- "@json:"
|
||||
- ''"@json:"''
|
||||
|
||||
Template
|
||||
~~~~~~~~
|
||||
@ -251,7 +337,7 @@ Template
|
||||
-config:
|
||||
template:
|
||||
- template:
|
||||
- "$ISODATE $HOST $MSG\n"
|
||||
- '"$ISODATE $HOST $MSG\n"'
|
||||
- template_escape:
|
||||
- "no"
|
||||
|
||||
@ -274,8 +360,8 @@ Rewrite
|
||||
- config:
|
||||
rewrite:
|
||||
- set:
|
||||
- "${.json.message}"
|
||||
- value : "$MESSAGE"
|
||||
- '"${.json.message}"'
|
||||
- value : '"$MESSAGE"'
|
||||
|
||||
Global options
|
||||
~~~~~~~~~~~~~~
|
||||
@ -353,7 +439,7 @@ Log
|
||||
- rewrite: r_set_message_to_MESSAGE
|
||||
- destination:
|
||||
- file:
|
||||
- "/tmp/json-input.log"
|
||||
- '"/tmp/json-input.log"'
|
||||
- template: t_gsoc2014
|
||||
- flags: final
|
||||
- channel:
|
||||
@ -366,4 +452,3 @@ Log
|
||||
- file:
|
||||
- "/tmp/all.log"
|
||||
- template: t_gsoc2014
|
||||
|
||||
|
1179
salt/modules/syslog_ng.py
Normal file
1179
salt/modules/syslog_ng.py
Normal file
File diff suppressed because it is too large
Load Diff
122
salt/states/syslog_ng.py
Normal file
122
salt/states/syslog_ng.py
Normal file
@ -0,0 +1,122 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
State module for syslog_ng
|
||||
==========================
|
||||
|
||||
:maintainer: Tibor Benke <btibi@sch.bme.hu>
|
||||
:maturity: new
|
||||
:depends: cmd, ps, syslog_ng
|
||||
:platform: all
|
||||
|
||||
Users can generate syslog-ng configuration files from YAML format or use
|
||||
plain ones and reload, start, or stop their syslog-ng by using this module.
|
||||
|
||||
Details
|
||||
-------
|
||||
|
||||
The service module is not available on all system, so this module includes
|
||||
:mod:`syslog_ng.reloaded <salt.states.syslog_ng.reloaded>`,
|
||||
:mod:`syslog_ng.stopped <salt.states.syslog_ng.stopped>`,
|
||||
and :mod:`syslog_ng.started <salt.states.syslog_ng.started>` functions.
|
||||
If the service module is available on the computers, users should use that.
|
||||
|
||||
Users can generate syslog-ng configuration with
|
||||
:mod:`syslog_ng.config <salt.states.syslog_ng.config>` function.
|
||||
For more information see :doc:`syslog-ng state usage </topics/tutorials/syslog_ng-state-usage>`.
|
||||
|
||||
Syslog-ng configuration file format
|
||||
-----------------------------------
|
||||
|
||||
The syntax of a configuration snippet in syslog-ng.conf:
|
||||
|
||||
..
|
||||
|
||||
object_type object_id {<options>};
|
||||
|
||||
|
||||
These constructions are also called statements. There are options inside of them:
|
||||
|
||||
..
|
||||
|
||||
option(parameter1, parameter2); option2(parameter1, parameter2);
|
||||
|
||||
You can find more information about syslog-ng's configuration syntax in the
|
||||
Syslog-ng Admin guide:
|
||||
http://www.balabit.com/sites/default/files/documents/syslog-ng-ose-3.5-guides/en/syslog-ng-ose-v3.5-guide-admin/html-single/index.html#syslog-ng.conf.5
|
||||
'''
|
||||
|
||||
from __future__ import generators, print_function, with_statement
|
||||
import logging
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def config(name,
|
||||
config,
|
||||
write=True):
|
||||
'''
|
||||
Builds syslog-ng configuration.
|
||||
|
||||
name : the id of the Salt document
|
||||
config : the parsed YAML code
|
||||
write : if True, it writes the config into the configuration file,
|
||||
otherwise just returns it
|
||||
'''
|
||||
return __salt__['syslog_ng.config'](name, config, write)
|
||||
|
||||
|
||||
def stopped(name=None):
|
||||
'''
|
||||
Kills syslog-ng.
|
||||
'''
|
||||
return __salt__['syslog_ng.stop'](name)
|
||||
|
||||
|
||||
def started(name=None,
|
||||
user=None,
|
||||
group=None,
|
||||
chroot=None,
|
||||
caps=None,
|
||||
no_caps=False,
|
||||
pidfile=None,
|
||||
enable_core=False,
|
||||
fd_limit=None,
|
||||
verbose=False,
|
||||
debug=False,
|
||||
trace=False,
|
||||
yydebug=False,
|
||||
persist_file=None,
|
||||
control=None,
|
||||
worker_threads=None,
|
||||
*args,
|
||||
**kwargs):
|
||||
'''
|
||||
Ensures, that syslog-ng is started via the given parameters.
|
||||
|
||||
Users shouldn't use this function, if the service module is available on
|
||||
their system.
|
||||
'''
|
||||
return __salt__['syslog_ng.start'](name=name,
|
||||
user=user,
|
||||
group=group,
|
||||
chroot=chroot,
|
||||
caps=caps,
|
||||
no_caps=no_caps,
|
||||
pidfile=pidfile,
|
||||
enable_core=enable_core,
|
||||
fd_limit=fd_limit,
|
||||
verbose=verbose,
|
||||
debug=debug,
|
||||
trace=trace,
|
||||
yydebug=yydebug,
|
||||
persist_file=persist_file,
|
||||
control=control,
|
||||
worker_threads=worker_threads)
|
||||
|
||||
|
||||
def reloaded(name):
|
||||
'''
|
||||
Reloads syslog-ng.
|
||||
'''
|
||||
return __salt__['syslog_ng.reload'](name)
|
285
tests/unit/modules/syslog_ng_test.py
Normal file
285
tests/unit/modules/syslog_ng_test.py
Normal file
@ -0,0 +1,285 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Test module for syslog_ng
|
||||
'''
|
||||
|
||||
# Import Salt Testing libs
|
||||
import salt
|
||||
from salttesting import skipIf, TestCase
|
||||
from salttesting.helpers import ensure_in_syspath
|
||||
from salttesting.mock import NO_MOCK, NO_MOCK_REASON, MagicMock, patch
|
||||
from textwrap import dedent
|
||||
|
||||
ensure_in_syspath('../../')
|
||||
|
||||
from salt.modules import syslog_ng
|
||||
|
||||
syslog_ng.__salt__ = {}
|
||||
syslog_ng.__opts__ = {}
|
||||
|
||||
_VERSION = "3.6.0alpha0"
|
||||
_MODULES = ("syslogformat,json-plugin,basicfuncs,afstomp,afsocket,cryptofuncs,"
|
||||
"afmongodb,dbparser,system-source,affile,pseudofile,afamqp,"
|
||||
"afsocket-notls,csvparser,linux-kmsg-format,afuser,confgen,afprog")
|
||||
|
||||
VERSION_OUTPUT = """syslog-ng {0}
|
||||
Installer-Version: {0}
|
||||
Revision:
|
||||
Compile-Date: Apr 4 2014 20:26:18
|
||||
Error opening plugin module; module='afsocket-tls', error='/home/tibi/install/syslog-ng/lib/syslog-ng/libafsocket-tls.so: undefined symbol: tls_context_setup_session'
|
||||
Available-Modules: {1}
|
||||
Enable-Debug: on
|
||||
Enable-GProf: off
|
||||
Enable-Memtrace: off
|
||||
Enable-IPv6: on
|
||||
Enable-Spoof-Source: off
|
||||
Enable-TCP-Wrapper: off
|
||||
Enable-Linux-Caps: off""".format(_VERSION, _MODULES)
|
||||
|
||||
STATS_OUTPUT = """SourceName;SourceId;SourceInstance;State;Type;Number
|
||||
center;;received;a;processed;0
|
||||
destination;#anon-destination0;;a;processed;0
|
||||
destination;#anon-destination1;;a;processed;0
|
||||
source;s_gsoc2014;;a;processed;0
|
||||
center;;queued;a;processed;0
|
||||
global;payload_reallocs;;a;processed;0
|
||||
global;sdata_updates;;a;processed;0
|
||||
global;msg_clones;;a;processed;0"""
|
||||
|
||||
_SYSLOG_NG_NOT_INSTALLED_RETURN_VALUE = {
|
||||
"retcode": -1, "stderr":
|
||||
"Unable to execute the command 'syslog-ng'. It is not in the PATH."
|
||||
}
|
||||
_SYSLOG_NG_CTL_NOT_INSTALLED_RETURN_VALUE = {
|
||||
"retcode": -1, "stderr":
|
||||
"Unable to execute the command 'syslog-ng-ctl'. It is not in the PATH."
|
||||
}
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class SyslogNGTestCase(TestCase):
|
||||
|
||||
def test_statement_without_options(self):
|
||||
s = syslog_ng.Statement("source", "s_local", options=[])
|
||||
b = s.build()
|
||||
self.assertEqual(dedent(
|
||||
"""\
|
||||
source s_local {
|
||||
};
|
||||
"""), b)
|
||||
|
||||
def test_non_empty_statement(self):
|
||||
o1 = syslog_ng.Option("file")
|
||||
o2 = syslog_ng.Option("tcp")
|
||||
s = syslog_ng.Statement("source", "s_local", options=[o1, o2])
|
||||
b = s.build()
|
||||
self.assertEqual(dedent(
|
||||
"""\
|
||||
source s_local {
|
||||
file(
|
||||
);
|
||||
tcp(
|
||||
);
|
||||
};
|
||||
"""), b)
|
||||
|
||||
def test_option_with_parameters(self):
|
||||
o1 = syslog_ng.Option("file")
|
||||
p1 = syslog_ng.SimpleParameter('"/var/log/messages"')
|
||||
p2 = syslog_ng.SimpleParameter()
|
||||
p3 = syslog_ng.TypedParameter()
|
||||
p3.type = "tls"
|
||||
p2.value = '"/var/log/syslog"'
|
||||
o1.add_parameter(p1)
|
||||
o1.add_parameter(p2)
|
||||
o1.add_parameter(p3)
|
||||
b = o1.build()
|
||||
self.assertEqual(dedent(
|
||||
"""\
|
||||
file(
|
||||
"/var/log/messages",
|
||||
"/var/log/syslog",
|
||||
tls(
|
||||
)
|
||||
);
|
||||
"""), b)
|
||||
|
||||
def test_parameter_with_values(self):
|
||||
p = syslog_ng.TypedParameter()
|
||||
p.type = "tls"
|
||||
v1 = syslog_ng.TypedParameterValue()
|
||||
v1.type = 'key_file'
|
||||
|
||||
v2 = syslog_ng.TypedParameterValue()
|
||||
v2.type = 'cert_file'
|
||||
|
||||
p.add_value(v1)
|
||||
p.add_value(v2)
|
||||
|
||||
b = p.build()
|
||||
self.assertEqual(dedent(
|
||||
"""\
|
||||
tls(
|
||||
key_file(
|
||||
),
|
||||
cert_file(
|
||||
)
|
||||
)"""), b)
|
||||
|
||||
def test_value_with_arguments(self):
|
||||
t = syslog_ng.TypedParameterValue()
|
||||
t.type = 'key_file'
|
||||
|
||||
a1 = syslog_ng.Argument('"/opt/syslog-ng/etc/syslog-ng/key.d/syslog-ng.key"')
|
||||
a2 = syslog_ng.Argument('"/opt/syslog-ng/etc/syslog-ng/key.d/syslog-ng.key"')
|
||||
|
||||
t.add_argument(a1)
|
||||
t.add_argument(a2)
|
||||
|
||||
b = t.build()
|
||||
self.assertEqual(dedent(
|
||||
'''\
|
||||
key_file(
|
||||
"/opt/syslog-ng/etc/syslog-ng/key.d/syslog-ng.key"
|
||||
"/opt/syslog-ng/etc/syslog-ng/key.d/syslog-ng.key"
|
||||
)'''), b)
|
||||
|
||||
def test_end_to_end_statement_generation(self):
|
||||
s = syslog_ng.Statement('source', 's_tls')
|
||||
|
||||
o = syslog_ng.Option('tcp')
|
||||
|
||||
ip = syslog_ng.TypedParameter('ip')
|
||||
ip.add_value(syslog_ng.SimpleParameterValue("'192.168.42.2'"))
|
||||
o.add_parameter(ip)
|
||||
|
||||
port = syslog_ng.TypedParameter('port')
|
||||
port.add_value(syslog_ng.SimpleParameterValue(514))
|
||||
o.add_parameter(port)
|
||||
|
||||
tls = syslog_ng.TypedParameter('tls')
|
||||
key_file = syslog_ng.TypedParameterValue('key_file')
|
||||
key_file.add_argument(syslog_ng.Argument('"/opt/syslog-ng/etc/syslog-ng/key.d/syslog-ng.key"'))
|
||||
cert_file = syslog_ng.TypedParameterValue('cert_file')
|
||||
cert_file.add_argument(syslog_ng.Argument('"/opt/syslog-ng/etc/syslog-ng/cert.d/syslog-ng.cert"'))
|
||||
peer_verify = syslog_ng.TypedParameterValue('peer_verify')
|
||||
peer_verify.add_argument(syslog_ng.Argument('optional-untrusted'))
|
||||
tls.add_value(key_file)
|
||||
tls.add_value(cert_file)
|
||||
tls.add_value(peer_verify)
|
||||
o.add_parameter(tls)
|
||||
|
||||
s.add_child(o)
|
||||
b = s.build()
|
||||
self.assertEqual(dedent(
|
||||
'''\
|
||||
source s_tls {
|
||||
tcp(
|
||||
ip(
|
||||
'192.168.42.2'
|
||||
),
|
||||
port(
|
||||
514
|
||||
),
|
||||
tls(
|
||||
key_file(
|
||||
"/opt/syslog-ng/etc/syslog-ng/key.d/syslog-ng.key"
|
||||
),
|
||||
cert_file(
|
||||
"/opt/syslog-ng/etc/syslog-ng/cert.d/syslog-ng.cert"
|
||||
),
|
||||
peer_verify(
|
||||
optional-untrusted
|
||||
)
|
||||
)
|
||||
);
|
||||
};
|
||||
'''), b)
|
||||
|
||||
def test_version(self):
|
||||
mock_return_value = {"retcode": 0, 'stdout': VERSION_OUTPUT}
|
||||
expected_output = {"retcode": 0, "stdout": "3.6.0alpha0"}
|
||||
mock_args = "syslog-ng -V"
|
||||
self._assert_template(mock_args,
|
||||
mock_return_value,
|
||||
function_to_call=syslog_ng.version,
|
||||
expected_output=expected_output)
|
||||
|
||||
def test_stats(self):
|
||||
mock_return_value = {"retcode": 0, 'stdout': STATS_OUTPUT}
|
||||
expected_output = {"retcode": 0, "stdout": STATS_OUTPUT}
|
||||
mock_args = "syslog-ng-ctl stats"
|
||||
self._assert_template(mock_args,
|
||||
mock_return_value,
|
||||
function_to_call=syslog_ng.stats,
|
||||
expected_output=expected_output)
|
||||
|
||||
def test_modules(self):
|
||||
mock_return_value = {"retcode": 0, 'stdout': VERSION_OUTPUT}
|
||||
expected_output = {"retcode": 0, "stdout": _MODULES}
|
||||
mock_args = "syslog-ng -V"
|
||||
self._assert_template(mock_args,
|
||||
mock_return_value,
|
||||
function_to_call=syslog_ng.modules,
|
||||
expected_output=expected_output)
|
||||
|
||||
def test_config_test_ok(self):
|
||||
mock_return_value = {"retcode": 0, "stderr": "", "stdout": "Syslog-ng startup text..."}
|
||||
mock_args = "syslog-ng --syntax-only"
|
||||
self._assert_template(mock_args,
|
||||
mock_return_value,
|
||||
function_to_call=syslog_ng.config_test,
|
||||
expected_output=mock_return_value)
|
||||
|
||||
def test_config_test_fails(self):
|
||||
mock_return_value = {"retcode": 1, 'stderr': "Syntax error...", "stdout": ""}
|
||||
mock_args = "syslog-ng --syntax-only"
|
||||
self._assert_template(mock_args,
|
||||
mock_return_value,
|
||||
function_to_call=syslog_ng.config_test,
|
||||
expected_output=mock_return_value)
|
||||
|
||||
def test_config_test_cfgfile(self):
|
||||
cfgfile = "/path/to/syslog-ng.conf"
|
||||
mock_return_value = {"retcode": 1, 'stderr': "Syntax error...", "stdout": ""}
|
||||
mock_args = "syslog-ng --syntax-only --cfgfile={0}".format(cfgfile)
|
||||
self._assert_template(mock_args,
|
||||
mock_return_value,
|
||||
function_to_call=syslog_ng.config_test,
|
||||
function_args={"cfgfile": cfgfile},
|
||||
expected_output=mock_return_value)
|
||||
|
||||
def _assert_template(self,
|
||||
mock_funtion_args,
|
||||
mock_return_value,
|
||||
function_to_call,
|
||||
expected_output,
|
||||
function_args=None):
|
||||
if function_args is None:
|
||||
function_args = {}
|
||||
|
||||
installed = True
|
||||
if not salt.utils.which("syslog-ng"):
|
||||
installed = False
|
||||
if "syslog-ng-ctl" in mock_funtion_args:
|
||||
expected_output = _SYSLOG_NG_CTL_NOT_INSTALLED_RETURN_VALUE
|
||||
else:
|
||||
expected_output = _SYSLOG_NG_NOT_INSTALLED_RETURN_VALUE
|
||||
|
||||
mock_function = MagicMock(return_value=mock_return_value)
|
||||
|
||||
with patch.dict(syslog_ng.__salt__, {'cmd.run_all': mock_function}):
|
||||
got = function_to_call(**function_args)
|
||||
self.assertEqual(expected_output, got)
|
||||
|
||||
if installed:
|
||||
self.assertTrue(mock_function.called)
|
||||
self.assertEqual(len(mock_function.call_args), 2)
|
||||
mock_param = mock_function.call_args
|
||||
self.assertTrue(mock_param[0][0].endswith(mock_funtion_args))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
|
||||
run_tests(SyslogNGTestCase, needs_daemon=False)
|
388
tests/unit/states/syslog_ng_test.py
Normal file
388
tests/unit/states/syslog_ng_test.py
Normal file
@ -0,0 +1,388 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Test module for syslog_ng state
|
||||
'''
|
||||
|
||||
import yaml
|
||||
import re
|
||||
import tempfile
|
||||
import os
|
||||
|
||||
from salttesting import skipIf, TestCase
|
||||
from salttesting.helpers import ensure_in_syspath
|
||||
from salttesting.mock import NO_MOCK, NO_MOCK_REASON, MagicMock, patch
|
||||
|
||||
ensure_in_syspath('../../')
|
||||
|
||||
from salt.states import syslog_ng
|
||||
from salt.modules import syslog_ng as syslog_ng_module
|
||||
|
||||
syslog_ng.__salt__ = {}
|
||||
syslog_ng_module.__salt__ = {}
|
||||
syslog_ng_module.__opts__ = {'test': False}
|
||||
|
||||
SOURCE_1_CONFIG = {
|
||||
"id": "s_tail",
|
||||
"config": (
|
||||
"""
|
||||
source:
|
||||
- file:
|
||||
- '"/var/log/apache/access.log"'
|
||||
- follow_freq : 1
|
||||
- flags:
|
||||
- no-parse
|
||||
- validate-utf8
|
||||
""")
|
||||
}
|
||||
|
||||
SOURCE_1_EXPECTED = (
|
||||
"""
|
||||
source s_tail {
|
||||
file(
|
||||
"/var/log/apache/access.log",
|
||||
follow_freq(1),
|
||||
flags(no-parse, validate-utf8)
|
||||
);
|
||||
};
|
||||
"""
|
||||
)
|
||||
|
||||
SOURCE_2_CONFIG = {
|
||||
"id": "s_gsoc2014",
|
||||
"config": (
|
||||
"""
|
||||
source:
|
||||
- tcp:
|
||||
- ip: '"0.0.0.0"'
|
||||
- port: 1234
|
||||
- flags: no-parse
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
SOURCE_2_EXPECTED = (
|
||||
"""
|
||||
source s_gsoc2014 {
|
||||
tcp(
|
||||
ip("0.0.0.0"),
|
||||
port(1234),
|
||||
flags(no-parse)
|
||||
);
|
||||
};"""
|
||||
)
|
||||
|
||||
FILTER_1_CONFIG = {
|
||||
"id": "f_json",
|
||||
"config": (
|
||||
"""
|
||||
filter:
|
||||
- match:
|
||||
- '"@json:"'
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
FILTER_1_EXPECTED = (
|
||||
"""
|
||||
filter f_json {
|
||||
match(
|
||||
"@json:"
|
||||
);
|
||||
};
|
||||
"""
|
||||
)
|
||||
|
||||
TEMPLATE_1_CONFIG = {
|
||||
"id": "t_demo_filetemplate",
|
||||
"config": (
|
||||
"""
|
||||
template:
|
||||
- template:
|
||||
- '"$ISODATE $HOST $MSG\n"'
|
||||
- template_escape:
|
||||
- "no"
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
TEMPLATE_1_EXPECTED = (
|
||||
"""
|
||||
template t_demo_filetemplate {
|
||||
template(
|
||||
"$ISODATE $HOST $MSG "
|
||||
);
|
||||
template_escape(
|
||||
no
|
||||
);
|
||||
};
|
||||
"""
|
||||
)
|
||||
|
||||
REWRITE_1_CONFIG = {
|
||||
"id": "r_set_message_to_MESSAGE",
|
||||
"config": (
|
||||
"""
|
||||
rewrite:
|
||||
- set:
|
||||
- '"${.json.message}"'
|
||||
- value : '"$MESSAGE"'
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
REWRITE_1_EXPECTED = (
|
||||
"""
|
||||
rewrite r_set_message_to_MESSAGE {
|
||||
set(
|
||||
"${.json.message}",
|
||||
value("$MESSAGE")
|
||||
);
|
||||
};
|
||||
"""
|
||||
)
|
||||
|
||||
LOG_1_CONFIG = {
|
||||
"id": "l_gsoc2014",
|
||||
"config": (
|
||||
"""
|
||||
log:
|
||||
- source: s_gsoc2014
|
||||
- junction:
|
||||
- channel:
|
||||
- filter: f_json
|
||||
- parser: p_json
|
||||
- rewrite: r_set_json_tag
|
||||
- rewrite: r_set_message_to_MESSAGE
|
||||
- destination:
|
||||
- file:
|
||||
- '"/tmp/json-input.log"'
|
||||
- template: t_gsoc2014
|
||||
- flags: final
|
||||
- channel:
|
||||
- filter: f_not_json
|
||||
- parser:
|
||||
- syslog-parser: []
|
||||
- rewrite: r_set_syslog_tag
|
||||
- flags: final
|
||||
- destination:
|
||||
- file:
|
||||
- '"/tmp/all.log"'
|
||||
- template: t_gsoc2014
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
LOG_1_EXPECTED = (
|
||||
"""
|
||||
log {
|
||||
source(s_gsoc2014);
|
||||
junction {
|
||||
channel {
|
||||
filter(f_json);
|
||||
parser(p_json);
|
||||
rewrite(r_set_json_tag);
|
||||
rewrite(r_set_message_to_MESSAGE);
|
||||
destination {
|
||||
file(
|
||||
"/tmp/json-input.log",
|
||||
template(t_gsoc2014)
|
||||
);
|
||||
};
|
||||
flags(final);
|
||||
};
|
||||
channel {
|
||||
filter(f_not_json);
|
||||
parser {
|
||||
syslog-parser(
|
||||
|
||||
);
|
||||
};
|
||||
rewrite(r_set_syslog_tag);
|
||||
flags(final);
|
||||
};
|
||||
};
|
||||
destination {
|
||||
file(
|
||||
"/tmp/all.log",
|
||||
template(t_gsoc2014)
|
||||
);
|
||||
};
|
||||
};
|
||||
"""
|
||||
)
|
||||
|
||||
OPTIONS_1_CONFIG = {
|
||||
"id": "global_options",
|
||||
"config": (
|
||||
"""
|
||||
options:
|
||||
- time_reap: 30
|
||||
- mark_freq: 10
|
||||
- keep_hostname: "yes"
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
OPTIONS_1_EXPECTED = (
|
||||
"""
|
||||
options {
|
||||
time_reap(30);
|
||||
mark_freq(10);
|
||||
keep_hostname(yes);
|
||||
};
|
||||
"""
|
||||
)
|
||||
|
||||
SHORT_FORM_CONFIG = {
|
||||
"id": "source.s_gsoc",
|
||||
"config": (
|
||||
"""
|
||||
- tcp:
|
||||
- ip: '"0.0.0.0"'
|
||||
- port: 1234
|
||||
- flags: no-parse
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
SHORT_FORM_EXPECTED = (
|
||||
"""
|
||||
source s_gsoc {
|
||||
tcp(
|
||||
ip(
|
||||
"0.0.0.0"
|
||||
),
|
||||
port(
|
||||
1234
|
||||
),
|
||||
flags(
|
||||
no-parse
|
||||
)
|
||||
);
|
||||
};
|
||||
"""
|
||||
)
|
||||
|
||||
GIVEN_CONFIG = {
|
||||
'id': "config.some_name",
|
||||
'config': (
|
||||
""" |
|
||||
source s_gsoc {
|
||||
tcp(
|
||||
ip(
|
||||
"0.0.0.0"
|
||||
),
|
||||
port(
|
||||
1234
|
||||
),
|
||||
flags(
|
||||
no-parse
|
||||
)
|
||||
);
|
||||
};
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
_SALT_VAR_WITH_MODULE_METHODS = {
|
||||
'syslog_ng.config': syslog_ng_module.config,
|
||||
'syslog_ng.start': syslog_ng_module.start,
|
||||
'syslog_ng.reload': syslog_ng_module.reload,
|
||||
'syslog_ng.stop': syslog_ng_module.stop,
|
||||
'syslog_ng.write_version': syslog_ng_module.write_version,
|
||||
'syslog_ng.write_config': syslog_ng_module.write_config
|
||||
}
|
||||
|
||||
|
||||
def remove_whitespaces(source):
|
||||
return re.sub(r"\s+", "", source.strip())
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
# @skipIf(syslog_ng.__virtual__() is False, 'Syslog-ng must be installed')
|
||||
class SyslogNGTestCase(TestCase):
|
||||
def test_generate_source_config(self):
|
||||
self._config_generator_template(SOURCE_1_CONFIG, SOURCE_1_EXPECTED)
|
||||
|
||||
def test_generate_log_config(self):
|
||||
self._config_generator_template(LOG_1_CONFIG, LOG_1_EXPECTED)
|
||||
|
||||
def test_generate_tcp_source_config(self):
|
||||
self._config_generator_template(SOURCE_2_CONFIG, SOURCE_2_EXPECTED)
|
||||
|
||||
def test_generate_filter_config(self):
|
||||
self._config_generator_template(FILTER_1_CONFIG, FILTER_1_EXPECTED)
|
||||
|
||||
def test_generate_template_config(self):
|
||||
self._config_generator_template(TEMPLATE_1_CONFIG, TEMPLATE_1_EXPECTED)
|
||||
|
||||
def test_generate_rewrite_config(self):
|
||||
self._config_generator_template(REWRITE_1_CONFIG, REWRITE_1_EXPECTED)
|
||||
|
||||
def test_generate_global_options_config(self):
|
||||
self._config_generator_template(OPTIONS_1_CONFIG, OPTIONS_1_EXPECTED)
|
||||
|
||||
def test_generate_short_form_statement(self):
|
||||
self._config_generator_template(SHORT_FORM_CONFIG, SHORT_FORM_EXPECTED)
|
||||
|
||||
def test_generate_given_config(self):
|
||||
self._config_generator_template(GIVEN_CONFIG, SHORT_FORM_EXPECTED)
|
||||
|
||||
def _config_generator_template(self, yaml_input, expected):
|
||||
parsed_yaml_config = yaml.load(yaml_input["config"])
|
||||
id = yaml_input["id"]
|
||||
|
||||
with patch.dict(syslog_ng.__salt__, _SALT_VAR_WITH_MODULE_METHODS):
|
||||
got = syslog_ng.config(id, config=parsed_yaml_config, write=False)
|
||||
config = got["changes"]["new"]
|
||||
self.assertEqual(remove_whitespaces(expected), remove_whitespaces(config))
|
||||
self.assertEqual(False, got["result"])
|
||||
|
||||
def test_write_config(self):
|
||||
yaml_inputs = (
|
||||
SOURCE_2_CONFIG, SOURCE_1_CONFIG, FILTER_1_CONFIG, TEMPLATE_1_CONFIG, REWRITE_1_CONFIG, LOG_1_CONFIG
|
||||
)
|
||||
expected_outputs = (
|
||||
SOURCE_2_EXPECTED, SOURCE_1_EXPECTED, FILTER_1_EXPECTED, TEMPLATE_1_EXPECTED, REWRITE_1_EXPECTED,
|
||||
LOG_1_EXPECTED
|
||||
)
|
||||
config_file_fd, config_file_name = tempfile.mkstemp()
|
||||
os.close(config_file_fd)
|
||||
|
||||
with patch.dict(syslog_ng.__salt__, _SALT_VAR_WITH_MODULE_METHODS):
|
||||
syslog_ng_module.set_config_file(config_file_name)
|
||||
syslog_ng_module.write_version("3.6")
|
||||
syslog_ng_module.write_config(config='@include "scl.conf"')
|
||||
|
||||
for i in yaml_inputs:
|
||||
parsed_yaml_config = yaml.load(i["config"])
|
||||
id = i["id"]
|
||||
got = syslog_ng.config(id, config=parsed_yaml_config, write=True)
|
||||
|
||||
written_config = ""
|
||||
with open(config_file_name, "r") as f:
|
||||
written_config = f.read()
|
||||
|
||||
config_without_whitespaces = remove_whitespaces(written_config)
|
||||
for i in expected_outputs:
|
||||
without_whitespaces = remove_whitespaces(i)
|
||||
self.assertIn(without_whitespaces, config_without_whitespaces)
|
||||
|
||||
syslog_ng_module.set_config_file("")
|
||||
os.remove(config_file_name)
|
||||
|
||||
def test_started_state_generate_valid_cli_command(self):
|
||||
mock_func = MagicMock(return_value={"retcode": 0, "stdout": "", "pid": 1000})
|
||||
|
||||
with patch.dict(syslog_ng.__salt__, _SALT_VAR_WITH_MODULE_METHODS):
|
||||
with patch.dict(syslog_ng_module.__salt__, {'cmd.run_all': mock_func}):
|
||||
got = syslog_ng.started(user="joe", group="users", enable_core=True)
|
||||
command = got["changes"]["new"]
|
||||
self.assertTrue(
|
||||
command.endswith("syslog-ng --user=joe --group=users --enable-core --cfgfile=/etc/syslog-ng.conf"))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
|
||||
run_tests(SyslogNGTestCase, needs_daemon=False)
|
Loading…
Reference in New Issue
Block a user