mirror of
https://github.com/Icinga/icinga-powershell-framework.git
synced 2025-12-21 07:10:15 -05:00
Merge pull request #163 from Icinga:feature/icinga2_plain_config_generator
Feature: Adds native Icinga config generation support and adds simple publish command Adds native support for writing Icinga 2 configuration for plugins and allows to easy publish new configurations for modules with the new Cmdlet Publish-IcingaPluginConfiguration
This commit is contained in:
commit
348fa773fd
5 changed files with 327 additions and 10 deletions
|
|
@ -16,7 +16,8 @@ Configuring Check-Commands
|
|||
|
||||
To get started, there are two ways to configure check command objects:
|
||||
|
||||
* [Automated configuration](icingaintegration/01-Director-Baskets.md) with Baskets
|
||||
* [Automated Icinga Director configuration](icingaintegration/01-Director-Baskets.md) with Baskets
|
||||
* [Automated Icinga 2 configuration](icingaintegration/04-Icinga-Config.md) with plain Icinga config
|
||||
* [Manual configuration](icingaintegration/02-Manual-Integration.md) of check commands
|
||||
* [Using PowerShell Arrays in Icinga](icingaintegration/03-PowerShell-Arrays.md)
|
||||
* [Windows Terminal Integration](icingaintegration/50-Windows-Terminal.md)
|
||||
|
|
@ -25,6 +25,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic
|
|||
* [#153](https://github.com/Icinga/icinga-powershell-framework/pull/153) Adds support to add a knowledge base id to `Exit-IcingaThrowException` for easier referencing. This should mostly be used for custom messages, as we should track the main knowledge base id's inside the messages directly. Native messages should be split in a hashtable with a `Message` and `IWKB` key
|
||||
* [#155](https://github.com/Icinga/icinga-powershell-framework/pull/155) Adds support to write all objects collected by `Get-IcingaWindowsInformation` into the Windows EventLog in case the debug output for the Icinga PowerShell Framework is enabled.
|
||||
* [#162](https://github.com/Icinga/icinga-powershell-framework/pull/162) Adds feature to test the length of plugin custom variables during config generation and throws error in case the total length is bigger than 64 digits, as imports into the Icinga Director by using baskets is not possible otherwise
|
||||
* [#163](https://github.com/Icinga/icinga-powershell-framework/pull/163) Adds native support for writing Icinga 2 configuration for plugins and allows to easy publish new configurations for modules with the new Cmdlet `Publish-IcingaPluginConfiguration`
|
||||
* [#164](https://github.com/Icinga/icinga-powershell-framework/pull/164) Adds `exit` after calling `icinga` on Windows Terminal integration to ensure the shell will close in case the Icinga shell is closed
|
||||
|
||||
### Bugfixes
|
||||
|
|
|
|||
56
doc/icingaintegration/04-Icinga-Config.md
Normal file
56
doc/icingaintegration/04-Icinga-Config.md
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# Icinga Config Generator
|
||||
|
||||
To make the integration as easy as possible, the Framework is shipping with an Icinga 2 configuration generator. Each Check-Plugin available within the Framework is able to auto-generate a Icinga config which can be copied to your Icinga 2 hosts.
|
||||
|
||||
## Generating Configuration
|
||||
|
||||
To automatically generate the Icinga configuration, open a PowerShell terminal and type in
|
||||
|
||||
```powershell
|
||||
icinga
|
||||
```
|
||||
|
||||
to load the Icinga PowerShell Framework.
|
||||
|
||||
Afterwards use the command
|
||||
|
||||
```powershell
|
||||
Get-IcingaCheckCommandConfig -IcingaConfig;
|
||||
```
|
||||
|
||||
to automatically generate the configuration for all found Check-Commands.
|
||||
|
||||
If you wish to specify specific commands only, you can filter them as well:
|
||||
|
||||
```powershell
|
||||
Get-IcingaCheckCommandConfig -CheckName Invoke-IcingaCheckBiosSerial, Invoke-IcingaCheckCPU -IcingaConfig;
|
||||
```
|
||||
|
||||
Last but not least you can output the Icinga configuration directly into a file. To do this, simply use the `OutDirectory` argument. You only require to specify a directory here, as the file including a timestamp is generated by the Cmdlet itself
|
||||
|
||||
```powershell
|
||||
Get-IcingaCheckCommandConfig -OutDirectory 'C:\Users\myuser\Documents\'
|
||||
```
|
||||
|
||||
Once the file is exported, you can copy the `.conf` files onto your Icinga 2 hosts to use them.
|
||||
|
||||
**Note:** Because of a possible configuration error cased by multiple `PowerShell Base` CheckCommands, it is generated separately. You only require this once on your system and is cross-compatible with every single CheckCommand.
|
||||
|
||||
## Custom File Names
|
||||
|
||||
You can modify the name of the output `.conf` file by using the `-FileName` argument in combination with the other arguments:
|
||||
|
||||
```powershell
|
||||
Get-IcingaCheckCommandConfig -CheckName Invoke-IcingaCheckBiosSerial, Invoke-IcingaCheckCPU -IcingaConfig -OutDirectory 'C:\Users\myuser\Documents\' -FileName 'IcingaForWindows';
|
||||
```
|
||||
|
||||
This will generate the plugins configuration `C:\Users\myuser\Documents\IcingaForWindows.conf` and `C:\Users\myuser\Documents\PowerShell_Base.conf`
|
||||
|
||||
The `.conf` ending is not required, as the Cmdlet will take care of that for you.
|
||||
|
||||
## Developer Note
|
||||
|
||||
The generated Icinga configuration will benefit from a detailed documentation of the module and each single argument. Descriptions for arguments are parsed into the commands description field, informing users of what the argument actually does. Furthermore arguments are automatically mapped to certain object types. A `switch` argument for example will always be rendered with a `set_if` flag, ensuring you only require to set the corresponding custom variable to true to set this argument.
|
||||
In addition `array` arguments use the Icinga DSL to properly build PowerShell arrays based on Icinga arrays.
|
||||
|
||||
This will increase the entire usability of the module and prevent you from having to document plugins multiple times.
|
||||
104
lib/core/framework/Publish-IcingaPluginConfiguration.psm1
Normal file
104
lib/core/framework/Publish-IcingaPluginConfiguration.psm1
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
<#
|
||||
.SYNOPSIS
|
||||
Fetches plugins within the namespace `Invoke-IcingaCheck*` for a given
|
||||
component name or the direct path and creates Icinga Director as well as
|
||||
Icinga 2 configuration files.
|
||||
|
||||
The configuration files are printed within a `config` folder of the
|
||||
specific module and splitted into `director` and `icinga`
|
||||
.DESCRIPTION
|
||||
etches plugins within the namespace `Invoke-IcingaCheck*` for a given
|
||||
component name or the direct path and creates Icinga Director as well as
|
||||
Icinga 2 configuration files.
|
||||
|
||||
The configuration files are printed within a `config` folder of the
|
||||
specific module and splitted into `director` and `icinga`
|
||||
.FUNCTIONALITY
|
||||
Creates Icinga 2 and Icinga Director configuration files for plugins
|
||||
.EXAMPLE
|
||||
PS>Publish-IcingaPluginConfiguration -ComponentName 'plugins';
|
||||
.EXAMPLE
|
||||
PS>Publish-IcingaPluginConfiguration -ComponentPath 'C:\Program Files\WindowsPowerShell\modules\icinga-powershell-plugins';
|
||||
.PARAMETER ComponentName
|
||||
The name of the component to lookup for plugins and write configuration for.
|
||||
The leading icinga-powershell- is not required and you should simply use the name,
|
||||
like 'plugins' or 'mssql'
|
||||
.PARAMETER ComponentPath
|
||||
The path to the root directory of a PowerShell Plugin repository, like
|
||||
'C:\Program Files\WindowsPowerShell\modules\icinga-powershell-plugins'
|
||||
.INPUTS
|
||||
System.String
|
||||
.LINK
|
||||
https://github.com/Icinga/icinga-powershell-framework
|
||||
#>
|
||||
|
||||
function Publish-IcingaPluginConfiguration()
|
||||
{
|
||||
param (
|
||||
[string]$ComponentName,
|
||||
[string]$ComponentPath
|
||||
);
|
||||
|
||||
if ([string]::IsNullOrEmpty($ComponentName) -And [string]::IsNullOrEmpty($ComponentPath)) {
|
||||
Write-IcingaConsoleError 'Please specify either a component name like "plugins" or set the component path to the root folder if a component, like "C:\Program Files\WindowsPowerShell\modules\icinga-powershell\plugins".';
|
||||
return;
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrEmpty($ComponentPath)) {
|
||||
$ComponentPath = Join-Path -Path (Get-IcingaFrameworkRootPath) -ChildPath ([string]::Format('icinga-powershell-{0}', $ComponentName));
|
||||
}
|
||||
|
||||
if ((Test-Path $ComponentPath) -eq $FALSE) {
|
||||
Write-IcingaConsoleError 'The path "{0}" for the Icinga for Windows component is not valid' -Objects $ComponentPath;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Import-Module $ComponentPath -Global -Force -ErrorAction Stop;
|
||||
} catch {
|
||||
[string]$Message = $_.Exception.Message;
|
||||
Write-IcingaConsoleError 'Failed to import the module on path "{0}". Please verify that this is a valid PowerShell module root folder. Exception: {1}{2}' -Objects $ComponentPath, (New-IcingaNewLine), $Message;
|
||||
return;
|
||||
}
|
||||
|
||||
$CheckCommands = Get-Command -ListImported -Name 'Invoke-IcingaCheck*' -ErrorAction SilentlyContinue;
|
||||
|
||||
if ($null -eq $CheckCommands) {
|
||||
Write-IcingaConsoleError 'No Icinga CheckCommands were configured for module "{0}". Please verify that this is a valid PowerShell module root folder. Exception: {1}{2}' -Objects $ComponentPath, (New-IcingaNewLine), $Message;
|
||||
return;
|
||||
}
|
||||
|
||||
[array]$CheckList = @();
|
||||
|
||||
[string]$BasketConfigDir = Join-Path -Path $ComponentPath -ChildPath 'config\director';
|
||||
[string]$IcingaConfigDir = Join-Path -Path $ComponentPath -ChildPath 'config\icinga';
|
||||
|
||||
if ((Test-Path $BasketConfigDir)) {
|
||||
Remove-Item -Path $BasketConfigDir -Recurse -Force | Out-Null;
|
||||
}
|
||||
if ((Test-Path $IcingaConfigDir)) {
|
||||
Remove-Item -Path $IcingaConfigDir -Recurse -Force | Out-Null;
|
||||
}
|
||||
|
||||
if ((Test-Path $BasketConfigDir) -eq $FALSE) {
|
||||
New-Item -Path $BasketConfigDir -ItemType Directory | Out-Null;
|
||||
}
|
||||
if ((Test-Path $IcingaConfigDir) -eq $FALSE) {
|
||||
New-Item -Path $IcingaConfigDir -ItemType Directory | Out-Null;
|
||||
}
|
||||
|
||||
foreach ($check in $CheckCommands) {
|
||||
[string]$CheckPath = $check.Module.ModuleBase;
|
||||
|
||||
if ($CheckPath.Contains($ComponentPath) -eq $FALSE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$CheckList += [string]$check;
|
||||
Get-IcingaCheckCommandConfig -CheckName $check -OutDirectory $BasketConfigDir -FileName $check;
|
||||
Get-IcingaCheckCommandConfig -CheckName $check -OutDirectory $IcingaConfigDir -FileName $check -IcingaConfig;
|
||||
}
|
||||
|
||||
Get-IcingaCheckCommandConfig -CheckName $CheckList -OutDirectory $BasketConfigDir -FileName ([string]::Format('{0}_Bundle', (Get-Culture).TextInfo.ToTitleCase($ComponentName)));
|
||||
Get-IcingaCheckCommandConfig -CheckName $CheckList -OutDirectory $IcingaConfigDir -FileName ([string]::Format('{0}_Bundle', (Get-Culture).TextInfo.ToTitleCase($ComponentName))) -IcingaConfig;
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
.FUNCTIONALITY
|
||||
This module is intended to be used to export one or all PowerShell-Modules with the namespace 'Invoke-IcingaCheck'.
|
||||
The JSON-Export, which will be egenerated through this module is structured like an Icinga-Director-JSON-Export, so it can be imported via the Icinga-Director the same way.
|
||||
The JSON-Export, which will be generated through this module is structured like an Icinga-Director-JSON-Export, so it can be imported via the Icinga-Director the same way.
|
||||
|
||||
.EXAMPLE
|
||||
PS>Get-IcingaCheckCommandConfig
|
||||
|
|
@ -47,7 +47,14 @@
|
|||
|
||||
.PARAMETER CheckName
|
||||
Used to specify an array of commands which should be exported.
|
||||
Seperated with ','
|
||||
Separated with ','
|
||||
|
||||
.PARAMETER FileName
|
||||
Define a custom file name for the exported `.json`/`.conf` file
|
||||
|
||||
.PARAMETER IcingaConfig
|
||||
Will switch the configuration generator to write plain Icinga 2 `.conf`
|
||||
files instead of Icinga Director Basket `.json` files
|
||||
|
||||
.INPUTS
|
||||
System.Array
|
||||
|
|
@ -65,7 +72,9 @@ function Get-IcingaCheckCommandConfig()
|
|||
{
|
||||
param(
|
||||
[array]$CheckName,
|
||||
[string]$OutDirectory
|
||||
[string]$OutDirectory = '',
|
||||
[string]$Filename,
|
||||
[switch]$IcingaConfig
|
||||
);
|
||||
|
||||
# Check whether all Checks will be exported or just the ones specified
|
||||
|
|
@ -161,7 +170,7 @@ function Get-IcingaCheckCommandConfig()
|
|||
}
|
||||
);
|
||||
|
||||
$Basket.Command[$Data.Name].vars.Add($parameter.Name, $FALSE);
|
||||
$Basket.Command[$Data.Name].vars.Add($IcingaCustomVariable.Replace('$', ''), $FALSE);
|
||||
|
||||
} elseif ($parameter.type.name -eq 'Array') {
|
||||
# Conditional whether type of parameter is array
|
||||
|
|
@ -322,15 +331,26 @@ function Get-IcingaCheckCommandConfig()
|
|||
}
|
||||
}
|
||||
|
||||
# Build Filename with given Timestamp
|
||||
[string]$FileType = '.json';
|
||||
if ($IcingaConfig) {
|
||||
$FileType = '.conf';
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrEmpty($Filename)) {
|
||||
$TimeStamp = (Get-Date -Format "MM-dd-yyyy-HH-mm-ffff");
|
||||
$FileName = "PowerShell_CheckCommands_$TimeStamp.json";
|
||||
$FileName = [string]::Format("PowerShell_CheckCommands_{0}{1}", $TimeStamp, $FileType);
|
||||
} else {
|
||||
if ($Filename.Contains($FileType) -eq $FALSE) {
|
||||
$Filename = [string]::Format('{0}{1}', $Filename, $FileType);
|
||||
}
|
||||
}
|
||||
|
||||
# Generate JSON Output from Hashtable
|
||||
$output = ConvertTo-Json -Depth 100 $Basket -Compress;
|
||||
|
||||
# Determine whether json output via powershell or in file (based on param -OutDirectory)
|
||||
if ([string]::IsNullOrEmpty($OutDirectory) -eq $false) {
|
||||
$ConfigDirectory = $OutDirectory;
|
||||
$OutDirectory = (Join-Path -Path $OutDirectory -ChildPath $FileName);
|
||||
if ((Test-Path($OutDirectory)) -eq $false) {
|
||||
New-Item -Path $OutDirectory -ItemType File -Force | Out-Null;
|
||||
|
|
@ -340,7 +360,11 @@ function Get-IcingaCheckCommandConfig()
|
|||
throw 'Failed to create specified directory. Please try again or use a different target location.';
|
||||
}
|
||||
|
||||
if ($IcingaConfig) {
|
||||
Write-IcingaPlainConfigurationFiles -Content $Basket -OutDirectory $ConfigDirectory -FileName $FileName;
|
||||
} else {
|
||||
Set-Content -Path $OutDirectory -Value $output;
|
||||
}
|
||||
|
||||
# Output-Text
|
||||
Write-IcingaConsoleNotice "The following commands have been exported:"
|
||||
|
|
@ -362,6 +386,137 @@ function Get-IcingaCheckCommandConfig()
|
|||
return $output;
|
||||
}
|
||||
|
||||
function Write-IcingaPlainConfigurationFiles()
|
||||
{
|
||||
param (
|
||||
$Content,
|
||||
$OutDirectory,
|
||||
$FileName
|
||||
);
|
||||
|
||||
$ConfigDirectory = $OutDirectory;
|
||||
$OutDirectory = (Join-Path -Path $OutDirectory -ChildPath $FileName);
|
||||
|
||||
$IcingaConfig = '';
|
||||
|
||||
foreach ($entry in $Content.Command.Keys) {
|
||||
$CheckCommand = $Content.Command[$entry];
|
||||
|
||||
# Skip PowerShell base, this is written at the end in a separate file
|
||||
if ($CheckCommand.object_name -eq 'PowerShell Base') {
|
||||
continue;
|
||||
}
|
||||
|
||||
# Create the CheckCommand object
|
||||
$IcingaConfig += [string]::Format('object CheckCommand "{0}" {{{1}', $CheckCommand.object_name, (New-IcingaNewLine));
|
||||
|
||||
# Import all defined import templates
|
||||
foreach ($import in $CheckCommand.imports) {
|
||||
$IcingaConfig += [string]::Format(' import "{0}"{1}', $import, (New-IcingaNewLine));
|
||||
}
|
||||
$IcingaConfig += New-IcingaNewLine;
|
||||
|
||||
if ($CheckCommand.arguments.Count -ne 0) {
|
||||
# Arguments for the configuration
|
||||
$IcingaConfig += ' arguments += {'
|
||||
$IcingaConfig += New-IcingaNewLine;
|
||||
|
||||
foreach ($argument in $CheckCommand.arguments.Keys) {
|
||||
$CheckArgument = $CheckCommand.arguments[$argument];
|
||||
|
||||
# Each single argument, like "-Verbosity" = {
|
||||
$IcingaConfig += [string]::Format(' "{0}" = {{{1}', $argument, (New-IcingaNewLine));
|
||||
|
||||
foreach ($argconfig in $CheckArgument.Keys) {
|
||||
$Value = '';
|
||||
|
||||
# Order is numeric -> no "" required
|
||||
if ($argconfig -eq 'order') {
|
||||
$StringFormater = ' {0} = {1}{2}';
|
||||
} else {
|
||||
# All other entries should be handled as strings and contain ""
|
||||
$StringFormater =' {0} = "{1}"{2}'
|
||||
}
|
||||
|
||||
# In case it is a hashtable, this is most likely a DSL function
|
||||
# We have to render it differently to also match the intends
|
||||
if ($CheckArgument[$argconfig] -is [Hashtable]) {
|
||||
$Value = $CheckArgument[$argconfig].body;
|
||||
$DSLArray = $Value.Split("`r`n");
|
||||
$Value = '';
|
||||
foreach ($item in $DSLArray) {
|
||||
if ([string]::IsNullOrEmpty($item)) {
|
||||
continue;
|
||||
}
|
||||
$Value += [string]::Format(' {0}{1}', $item, (New-IcingaNewLine));
|
||||
}
|
||||
$Value = $Value.Substring(0, $Value.Length - 2);
|
||||
$StringFormater =' {0} = {{{{{2}{1}{2} }}}}{2}'
|
||||
} else {
|
||||
# All other values besides DSL
|
||||
$Value = $CheckArgument[$argconfig];
|
||||
}
|
||||
|
||||
# Read description from our variables
|
||||
if ($argconfig -eq 'value') {
|
||||
foreach ($item in $Content.DataField.Keys) {
|
||||
$DataField = $Content.DataField[$item];
|
||||
|
||||
if ($Value.Contains($DataField.varname)) {
|
||||
if ([string]::IsNullOrEmpty($DataField.description)) {
|
||||
break;
|
||||
}
|
||||
$IcingaConfig += [string]::Format(' description = "{0}"{1}', $DataField.description.Replace("`r`n", ''), (New-IcingaNewLine));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Write the argument to your CheckCommand
|
||||
$IcingaConfig += [string]::Format($StringFormater, $argconfig, $Value, (New-IcingaNewLine));
|
||||
}
|
||||
|
||||
# Close this specific argument
|
||||
$IcingaConfig += ' }'
|
||||
$IcingaConfig += New-IcingaNewLine;
|
||||
}
|
||||
|
||||
# Close all arguments content
|
||||
$IcingaConfig += New-IcingaNewLine;
|
||||
$IcingaConfig += ' }'
|
||||
}
|
||||
|
||||
# In case we pre-define custom variables, we should add them here
|
||||
if ($CheckCommand.vars.Count -ne 0) {
|
||||
$IcingaConfig += New-IcingaNewLine;
|
||||
|
||||
foreach ($var in $CheckCommand.vars.Keys) {
|
||||
$Value = $CheckCommand.vars[$var];
|
||||
$IcingaConfig += [string]::Format(' vars.{0} = {1}{2}', $var, $Value, (New-IcingaNewLine));
|
||||
}
|
||||
}
|
||||
|
||||
# Close the CheckCommand object
|
||||
$IcingaConfig += '}';
|
||||
if ($Content.Command.Count -gt 2) {
|
||||
$IcingaConfig += New-IcingaNewLine;
|
||||
$IcingaConfig += New-IcingaNewLine;
|
||||
}
|
||||
}
|
||||
|
||||
# Write the PowerShell Base command to a separate file for Icinga 2 configuration
|
||||
[string]$PowerShellBase = [string]::Format('object CheckCommand "PowerShell Base" {{{0}', (New-IcingaNewLine));
|
||||
$PowerShellBase += [string]::Format(' import "plugin-check-command"{0}', (New-IcingaNewLine));
|
||||
$PowerShellBase += [string]::Format(' command = [{0}', (New-IcingaNewLine));
|
||||
$PowerShellBase += [string]::Format(' "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"{0}', (New-IcingaNewLine));
|
||||
$PowerShellBase += [string]::Format(' ]{0}', (New-IcingaNewLine));
|
||||
$PowerShellBase += [string]::Format(' timeout = 3m{0}', (New-IcingaNewLine));
|
||||
$PowerShellBase += '}';
|
||||
|
||||
Set-Content -Path (Join-Path -Path $ConfigDirectory -ChildPath 'PowerShell_Base.conf') -Value $PowerShellBase;
|
||||
Set-Content -Path $OutDirectory -Value $IcingaConfig;
|
||||
}
|
||||
|
||||
function Add-PowerShellDataList()
|
||||
{
|
||||
param(
|
||||
|
|
|
|||
Loading…
Reference in a new issue