diff options
author | Andrew Saraceni <andrew.saraceni@gmail.com> | 2017-08-15 07:13:14 +0200 |
---|---|---|
committer | Brian Coca <bcoca@users.noreply.github.com> | 2017-08-15 07:13:14 +0200 |
commit | bb7813f16f19023903f721d5921c31c109ba3e68 (patch) | |
tree | 8e143d44904e4c6747ea3be67ba613cbe53a3edd | |
parent | ACI Subnet: New Module (#28202) (diff) | |
download | ansible-bb7813f16f19023903f721d5921c31c109ba3e68.tar.xz ansible-bb7813f16f19023903f721d5921c31c109ba3e68.zip |
New Module: Write Windows event log entries (win_eventlog_entry) (#27828)
* initial commit for win_eventlog_entry module
* added test module for integration tests and minor documentation fixes
7 files changed, 416 insertions, 0 deletions
diff --git a/lib/ansible/modules/windows/win_eventlog_entry.ps1 b/lib/ansible/modules/windows/win_eventlog_entry.ps1 new file mode 100644 index 0000000000..e40bdea0a4 --- /dev/null +++ b/lib/ansible/modules/windows/win_eventlog_entry.ps1 @@ -0,0 +1,106 @@ +#!powershell + +# (c) 2017, Andrew Saraceni <andrew.saraceni@gmail.com> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +#Requires -Module Ansible.ModuleUtils.Legacy.psm1 + +$ErrorActionPreference = "Stop" + +function Test-LogExistence { + <# + .SYNOPSIS + Get information on a log's existence. + #> + param( + [String]$LogName + ) + + $log_exists = $false + $log = Get-EventLog -List | Where-Object {$_.Log -eq $LogName} + if ($log) { + $log_exists = $true + } + return $log_exists +} + +function Test-SourceExistence { + <# + .SYNOPSIS + Get information on a source's existence. + #> + param( + [String]$LogName, + [String]$SourceName + ) + + $source_exists = [System.Diagnostics.EventLog]::SourceExists($SourceName) + + if ($source_exists) { + $source_log = [System.Diagnostics.EventLog]::LogNameFromSourceName($SourceName, ".") + if ($source_log -ne $LogName) { + Fail-Json -obj $result -message "Source $SourceName does not belong to log $LogName and cannot be written to" + } + } + + return $source_exists +} + +$params = Parse-Args $args -supports_check_mode $true +$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false + +$log = Get-AnsibleParam -obj $params -name "log" -type "str" -failifempty $true +$source = Get-AnsibleParam -obj $params -name "source" -type "str" -failifempty $true +$event_id = Get-AnsibleParam -obj $params -name "event_id" -type "int" -failifempty $true +$message = Get-AnsibleParam -obj $params -name "message" -type "str" -failifempty $true +$entry_type = Get-AnsibleParam -obj $params -name "entry_type" -type "str" -validateset "Error","FailureAudit","Information","SuccessAudit","Warning" +$category = Get-AnsibleParam -obj $params -name "category" -type "int" +$raw_data = Get-AnsibleParam -obj $params -name "raw_data" -type "str" + +$result = @{ + changed = $false +} + +$log_exists = Test-LogExistence -LogName $log +if (!$log_exists) { + Fail-Json -obj $result -message "Log $log does not exist and cannot be written to" +} + +$source_exists = Test-SourceExistence -LogName $log -SourceName $source +if (!$source_exists) { + Fail-Json -obj $result -message "Source $source does not exist" +} + +if ($event_id -lt 0 -or $event_id -gt 65535) { + Fail-Json -obj $result -message "Event ID must be between 0 and 65535" +} + +$write_params = @{ + LogName = $log + Source = $source + EventId = $event_id + Message = $message +} + +try { + if ($entry_type) { + $write_params.EntryType = $entry_type + } + if ($category) { + $write_params.Category = $category + } + if ($raw_data) { + $write_params.RawData = [Byte[]]($raw_data -split ",") + } + + if (!$check_mode) { + Write-EventLog @write_params + } + $result.changed = $true + $result.msg = "Entry added to log $log from source $source" +} +catch { + Fail-Json -obj $result -message $_.Exception.Message +} + +Exit-Json -obj $result diff --git a/lib/ansible/modules/windows/win_eventlog_entry.py b/lib/ansible/modules/windows/win_eventlog_entry.py new file mode 100644 index 0000000000..ffed384d4a --- /dev/null +++ b/lib/ansible/modules/windows/win_eventlog_entry.py @@ -0,0 +1,78 @@ +#!/usr/bin/python + +# (c) 2017, Andrew Saraceni <andrew.saraceni@gmail.com> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +ANSIBLE_METADATA = {'metadata_version': '1.0', + 'status': ['preview'], + 'supported_by': 'community'} + +DOCUMENTATION = r''' +--- +module: win_eventlog_entry +version_added: "2.4" +short_description: Write entries to Windows event logs +description: + - Write log entries to a given event log from a specified source. +options: + log: + description: + - Name of the event log to write an entry to. + required: true + source: + description: + - Name of the log source to indicate where the entry is from. + required: true + event_id: + description: + - The numeric event identifier for the entry. + - Value must be between 0 and 65535. + required: true + message: + description: + - The message for the given log entry. + required: true + entry_type: + description: + - Indicates the entry being written to the log is of a specific type. + choices: + - Error + - FailureAudit + - Information + - SuccessAudit + - Warning + category: + description: + - A numeric task category associated with the category message file for the log source. + raw_data: + description: + - Binary data associated with the log entry. + - Value must be a comma-separated array of 8-bit unsigned integers (0 to 255). +notes: + - This module will always report a change when writing an event entry. +author: + - Andrew Saraceni (@andrewsaraceni) +''' + +EXAMPLES = r''' +- name: Write an entry to a Windows event log + win_eventlog_entry: + log: MyNewLog + source: NewLogSource1 + event_id: 1234 + message: This is a test log entry. + +- name: Write another entry to a different Windows event log + win_eventlog_entry: + log: AnotherLog + source: MyAppSource + event_id: 5000 + message: An error has occurred. + entry_type: Error + category: 5 + raw_data: 10,20 +''' + +RETURN = r''' +# Default return values +''' diff --git a/test/integration/targets/win_eventlog_entry/aliases b/test/integration/targets/win_eventlog_entry/aliases new file mode 100644 index 0000000000..c6d6198167 --- /dev/null +++ b/test/integration/targets/win_eventlog_entry/aliases @@ -0,0 +1 @@ +windows/ci/group3 diff --git a/test/integration/targets/win_eventlog_entry/defaults/main.yml b/test/integration/targets/win_eventlog_entry/defaults/main.yml new file mode 100644 index 0000000000..611d16ec0e --- /dev/null +++ b/test/integration/targets/win_eventlog_entry/defaults/main.yml @@ -0,0 +1,6 @@ +win_test_log_source: + log: WinEventLogEntryTest + source: WinEventLogEntrySource +win_test_log_source_extra: + log: ExtraWinEventLogEntryTest + source: ExtraWinEventLogEntrySource diff --git a/test/integration/targets/win_eventlog_entry/library/test_win_eventlog_entry.ps1 b/test/integration/targets/win_eventlog_entry/library/test_win_eventlog_entry.ps1 new file mode 100644 index 0000000000..6c26cd3f59 --- /dev/null +++ b/test/integration/targets/win_eventlog_entry/library/test_win_eventlog_entry.ps1 @@ -0,0 +1,33 @@ +#!powershell + +# (c) 2017, Andrew Saraceni <andrew.saraceni@gmail.com> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +#Requires -Module Ansible.ModuleUtils.Legacy.psm1 + +# Test module used to grab the latest entry from an event log and output its properties + +$ErrorActionPreference = "Stop" + +$params = Parse-Args $args -supports_check_mode $true +$log = Get-AnsibleParam -obj $params -name "log" -type "str" -failifempty $true + +$result = @{ + changed = $false +} + +try { + $log_entry = Get-EventLog -LogName $log | Select-Object -First 1 -Property * +} +catch { + Fail-Json -obj $result -message "Could not find any entries for log $log" +} + +$result.source = $log_entry.Source +$result.event_id = $log_entry.EventID +$result.message = $log_entry.Message +$result.entry_type = $log_entry.EntryType.ToString() +$result.category = $log_entry.CategoryNumber +$result.raw_data = $log_entry.Data -join "," + +Exit-Json -obj $result diff --git a/test/integration/targets/win_eventlog_entry/tasks/main.yml b/test/integration/targets/win_eventlog_entry/tasks/main.yml new file mode 100644 index 0000000000..9a1790a592 --- /dev/null +++ b/test/integration/targets/win_eventlog_entry/tasks/main.yml @@ -0,0 +1,33 @@ +# win_shell invocations can eventually be replaced with win_eventlog +- name: Remove potentially leftover test logs and sources + win_shell: Remove-EventLog -LogName "{{ item.log }}" -ErrorAction SilentlyContinue + with_items: + - "{{ win_test_log_source }}" + - "{{ win_test_log_source_extra }}" + failed_when: no + +- name: Add new test logs and sources + win_shell: New-EventLog -LogName "{{ item.log }}" -Source "{{ item.source }}" + with_items: + - "{{ win_test_log_source }}" + - "{{ win_test_log_source_extra }}" + +- name: Run tests for win_eventlog_entry + block: + + - name: Test in normal mode + include_tasks: tests.yml + vars: + in_check_mode: no + + - name: Test in check-mode + include_tasks: tests.yml + vars: + in_check_mode: yes + check_mode: yes + +- name: Remove test logs and sources + win_shell: Remove-EventLog -LogName "{{ item.log }}" + with_items: + - "{{ win_test_log_source }}" + - "{{ win_test_log_source_extra }}" diff --git a/test/integration/targets/win_eventlog_entry/tasks/tests.yml b/test/integration/targets/win_eventlog_entry/tasks/tests.yml new file mode 100644 index 0000000000..17b78eb0ef --- /dev/null +++ b/test/integration/targets/win_eventlog_entry/tasks/tests.yml @@ -0,0 +1,159 @@ +# Test code for win_eventlog_entry + +# (c) 2017, Andrew Saraceni <andrew.saraceni@gmail.com> +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Add entry to fake log + win_eventlog_entry: + log: FakeLogName + source: "{{ win_test_log_source.source }}" + event_id: 12345 + message: This is a test log entry message + register: add_entry_to_fake_log + failed_when: add_entry_to_fake_log.changed != false or add_entry_to_fake_log.msg != "Log FakeLogName does not exist and cannot be written to" + + +- name: Add entry from fake source + win_eventlog_entry: + log: "{{ win_test_log_source.log }}" + source: FakeSourceName + event_id: 12345 + message: This is a test log entry message + register: add_entry_from_fake_source + failed_when: add_entry_from_fake_source.changed != false or add_entry_from_fake_source.msg != "Source FakeSourceName does not exist" + + +- name: Add entry with invalid event_id + win_eventlog_entry: + log: "{{ win_test_log_source.log }}" + source: "{{ win_test_log_source.source }}" + event_id: 67000 + message: This is a test log entry message + register: add_entry_with_invalid_event_id + failed_when: add_entry_with_invalid_event_id.changed != false or add_entry_with_invalid_event_id.msg != "Event ID must be between 0 and 65535" + + +- name: Add entry from other log source + win_eventlog_entry: + log: "{{ win_test_log_source.log }}" + source: "{{ win_test_log_source_extra.source }}" + event_id: 12345 + message: This is a test log entry message + register: add_entry_from_other_log_source + failed_when: add_entry_from_other_log_source.changed != false or add_entry_from_other_log_source.msg != "Source {{ win_test_log_source_extra.source }} does not belong to log {{ win_test_log_source.log }} and cannot be written to" + + +- name: Add entry + win_eventlog_entry: &wele + log: "{{ win_test_log_source.log }}" + source: "{{ win_test_log_source.source }}" + event_id: 12345 + message: This is a test log entry message + register: add_entry + +- name: Test add_entry + assert: + that: + - add_entry.changed == true + - add_entry.msg == "Entry added to log {{ win_test_log_source.log }} from source {{ win_test_log_source.source }}" + +- name: Test add_entry count (normal mode) + win_shell: (Get-EventLog -LogName "{{ win_test_log_source.log }}").Count + register: add_entry_count + failed_when: add_entry_count.stdout_lines[0] != "1" + when: not in_check_mode + +- name: Test add_entry result (normal mode) + test_win_eventlog_entry: + log: "{{ win_test_log_source.log }}" + register: add_entry_result + when: not in_check_mode + +- name: Test add_entry_result (normal mode) + assert: + that: + - add_entry_result.source == win_test_log_source.source + - add_entry_result.event_id == 12345 + - add_entry_result.message == "This is a test log entry message" + when: not in_check_mode + + +- name: Add entry (again) + win_eventlog_entry: *wele + register: add_entry_again + +- name: Test add_entry_again (normal mode) + assert: + that: + - add_entry_again.changed == true + - add_entry_again.msg == "Entry added to log {{ win_test_log_source.log }} from source {{ win_test_log_source.source }}" + when: not in_check_mode + +- name: Test add_entry_again count (normal mode) + win_shell: (Get-EventLog -LogName "{{ win_test_log_source.log }}").Count + register: add_entry_again_count + failed_when: add_entry_again_count.stdout_lines[0] != "2" + when: not in_check_mode + + +- name: Add entry all options + win_eventlog_entry: &wele_ao + <<: *wele + event_id: 500 + message: This is a test error message + entry_type: Error + category: 5 + raw_data: 10,20 + register: add_entry_all_options + +- name: Test add_entry_all_options + assert: + that: + - add_entry_all_options.changed == true + - add_entry_all_options.msg == "Entry added to log {{ win_test_log_source.log }} from source {{ win_test_log_source.source }}" + +- name: Test add_entry_all_options count (normal mode) + win_shell: (Get-EventLog -LogName "{{ win_test_log_source.log }}").Count + register: add_entry_all_options_count + failed_when: add_entry_all_options_count.stdout_lines[0] != "3" + when: not in_check_mode + +- name: Test add_entry_all_options result (normal mode) + test_win_eventlog_entry: + log: "{{ win_test_log_source.log }}" + register: add_entry_all_options_result + when: not in_check_mode + +- name: Test add_entry_all_options_result (normal mode) + assert: + that: + - add_entry_all_options_result.source == win_test_log_source.source + - add_entry_all_options_result.event_id == 500 + - add_entry_all_options_result.message == "This is a test error message" + - add_entry_all_options_result.entry_type == "Error" + - add_entry_all_options_result.category == 5 + - add_entry_all_options_result.raw_data == "10,20" + when: not in_check_mode + + +- name: Add entry all options (again) + win_eventlog_entry: *wele_ao + register: add_entry_all_options_again + +- name: Test add_entry_all_options_again (normal mode) + assert: + that: + - add_entry_all_options_again.changed == true + - add_entry_all_options_again.msg == "Entry added to log {{ win_test_log_source.log }} from source {{ win_test_log_source.source }}" + when: not in_check_mode + +- name: Test add_entry_all_options_again count (normal mode) + win_shell: (Get-EventLog -LogName "{{ win_test_log_source.log }}").Count + register: add_entry_all_options_again_count + failed_when: add_entry_all_options_again_count.stdout_lines[0] != "4" + when: not in_check_mode + + +- name: Clear event log entries + win_shell: Clear-EventLog -LogName "{{ win_test_log_source.log }}" + when: not in_check_mode |