mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Win chocolatey facts module (#46610)
* add module win_chocolatey_facts * rename example name * fix ansible-test errors * add integration tests * fix integration test * implementation of improvement proposals * implementation feedback * implementation feedback * fix trailing-whitespace * implementation feedback * fix version * fix lint * add test targets * Updated modules docs and tests Co-authored-by: Simon Baerlocher <sbaerlocher@users.noreply.github.com>
This commit is contained in:
parent
a7425a7e79
commit
bc6d441cf2
4 changed files with 391 additions and 0 deletions
182
lib/ansible/modules/windows/win_chocolatey_facts.ps1
Normal file
182
lib/ansible/modules/windows/win_chocolatey_facts.ps1
Normal file
|
@ -0,0 +1,182 @@
|
|||
#!powershell
|
||||
|
||||
# Copyright: (c) 2018, Ansible Project
|
||||
# Copyright: (c) 2018, Simon Baerlocher <s.baerlocher@sbaerlocher.ch>
|
||||
# Copyright: (c) 2018, ITIGO AG <opensource@itigo.ch>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
#Requires -Module Ansible.ModuleUtils.ArgvParser
|
||||
#Requires -Module Ansible.ModuleUtils.CommandUtil
|
||||
#Requires -Module Ansible.ModuleUtils.Legacy
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
Set-StrictMode -Version 2.0
|
||||
|
||||
# Create a new result object
|
||||
$result = @{
|
||||
changed = $false
|
||||
ansible_facts = @{
|
||||
ansible_chocolatey = @{
|
||||
config = @{}
|
||||
feature = @{}
|
||||
sources = @()
|
||||
packages = @()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$choco_app = Get-Command -Name choco.exe -CommandType Application -ErrorAction SilentlyContinue
|
||||
if (-not $choco_app) {
|
||||
Fail-Json -obj $result -message "Failed to find Chocolatey installation, make sure choco.exe is in the PATH env value"
|
||||
}
|
||||
|
||||
Function Get-ChocolateyFeature {
|
||||
|
||||
param($choco_app)
|
||||
|
||||
$command = Argv-ToString -arguments $choco_app.Path, "feature", "list", "-r"
|
||||
$res = Run-Command -command $command
|
||||
if ($res.rc -ne 0) {
|
||||
$result.stdout = $res.stdout
|
||||
$result.stderr = $res.stderr
|
||||
$result.rc = $res.rc
|
||||
Fail-Json -obj $result -message "Failed to list Chocolatey features, see stderr"
|
||||
}
|
||||
|
||||
$feature_info = @{}
|
||||
$res.stdout -split "`r`n" | Where-Object { $_ -ne "" } | ForEach-Object {
|
||||
$feature_split = $_ -split "\|"
|
||||
$feature_info."$($feature_split[0])" = $feature_split[1] -eq "Enabled"
|
||||
}
|
||||
$result.ansible_facts.ansible_chocolatey.feature = $feature_info
|
||||
}
|
||||
|
||||
Function Get-ChocolateyConfig {
|
||||
|
||||
param($choco_app)
|
||||
|
||||
$choco_config_path = "$(Split-Path -Path (Split-Path -Path $choco_app.Path))\config\chocolatey.config"
|
||||
if (-not (Test-Path -Path $choco_config_path)) {
|
||||
Fail-Json -obj $result -message "Expecting Chocolatey config file to exist at '$choco_config_path'"
|
||||
}
|
||||
|
||||
try {
|
||||
[xml]$choco_config = Get-Content -Path $choco_config_path
|
||||
} catch {
|
||||
Fail-Json -obj $result -message "Failed to parse Chocolatey config file at '$choco_config_path': $($_.Exception.Message)"
|
||||
}
|
||||
|
||||
$config_info = @{}
|
||||
foreach ($config in $choco_config.chocolatey.config.GetEnumerator()) {
|
||||
# try and parse as a boot, then an int, fallback to string
|
||||
try {
|
||||
$value = [System.Boolean]::Parse($config.value)
|
||||
} catch {
|
||||
try {
|
||||
$value = [System.Int32]::Parse($config.value)
|
||||
} catch {
|
||||
$value = $config.value
|
||||
}
|
||||
}
|
||||
$config_info."$($config.key)" = $value
|
||||
}
|
||||
$result.ansible_facts.ansible_chocolatey.config = $config_info
|
||||
}
|
||||
|
||||
Function Get-ChocolateyPackages {
|
||||
|
||||
param($choco_app)
|
||||
|
||||
$command = Argv-ToString -arguments $choco_app.Path, "list", "--local-only", "-r"
|
||||
$res = Run-Command -command $command
|
||||
if ($res.rc -ne 0) {
|
||||
$result.stdout = $res.stdout
|
||||
$result.stderr = $res.stderr
|
||||
$result.rc = $res.rc
|
||||
Fail-Json -obj $result -message "Failed to list Chocolatey Packages, see stderr"
|
||||
}
|
||||
|
||||
$packages_info = [System.Collections.ArrayList]@()
|
||||
$res.stdout -split "`r`n" | Where-Object { $_ -ne "" } | ForEach-Object {
|
||||
$packages_split = $_ -split "\|"
|
||||
$package_info = @{
|
||||
package = $packages_split[0]
|
||||
version = $packages_split[1]
|
||||
}
|
||||
$packages_info.Add($package_info) > $null
|
||||
}
|
||||
$result.ansible_facts.ansible_chocolatey.packages = $packages_info
|
||||
}
|
||||
|
||||
Function Get-ChocolateySources {
|
||||
param($choco_app)
|
||||
|
||||
$choco_config_path = "$(Split-Path -Path (Split-Path -Path $choco_app.Path))\config\chocolatey.config"
|
||||
if (-not (Test-Path -LiteralPath $choco_config_path)) {
|
||||
Fail-Json -obj $result -message "Expecting Chocolatey config file to exist at '$choco_config_path'"
|
||||
}
|
||||
|
||||
try {
|
||||
[xml]$choco_config = Get-Content -Path $choco_config_path
|
||||
} catch {
|
||||
Fail-Json -obj $result -message "Failed to parse Chocolatey config file at '$choco_config_path': $($_.Exception.Message)"
|
||||
}
|
||||
|
||||
$sources = [System.Collections.ArrayList]@()
|
||||
foreach ($xml_source in $choco_config.chocolatey.sources.GetEnumerator()) {
|
||||
$source_username = $xml_source.Attributes.GetNamedItem("user")
|
||||
if ($null -ne $source_username) {
|
||||
$source_username = $source_username.Value
|
||||
}
|
||||
|
||||
# 0.9.9.9+
|
||||
$priority = $xml_source.Attributes.GetNamedItem("priority")
|
||||
if ($null -ne $priority) {
|
||||
$priority = [int]$priority.Value
|
||||
}
|
||||
|
||||
# 0.9.10+
|
||||
$certificate = $xml_source.Attributes.GetNamedItem("certificate")
|
||||
if ($null -ne $certificate) {
|
||||
$certificate = $certificate.Value
|
||||
}
|
||||
|
||||
# 0.10.4+
|
||||
$bypass_proxy = $xml_source.Attributes.GetNamedItem("bypassProxy")
|
||||
if ($null -ne $bypass_proxy) {
|
||||
$bypass_proxy = [System.Convert]::ToBoolean($bypass_proxy.Value)
|
||||
}
|
||||
$allow_self_service = $xml_source.Attributes.GetNamedItem("selfService")
|
||||
if ($null -ne $allow_self_service) {
|
||||
$allow_self_service = [System.Convert]::ToBoolean($allow_self_service.Value)
|
||||
}
|
||||
|
||||
# 0.10.8+
|
||||
$admin_only = $xml_source.Attributes.GetNamedItem("adminOnly")
|
||||
if ($null -ne $admin_only) {
|
||||
$admin_only = [System.Convert]::ToBoolean($admin_only.Value)
|
||||
}
|
||||
|
||||
$source_info = @{
|
||||
name = $xml_source.id
|
||||
source = $xml_source.value
|
||||
disabled = [System.Convert]::ToBoolean($xml_source.disabled)
|
||||
source_username = $source_username
|
||||
priority = $priority
|
||||
certificate = $certificate
|
||||
bypass_proxy = $bypass_proxy
|
||||
allow_self_service = $allow_self_service
|
||||
admin_only = $admin_only
|
||||
}
|
||||
$sources.Add($source_info) > $null
|
||||
}
|
||||
$result.ansible_facts.ansible_chocolatey.sources = $sources
|
||||
}
|
||||
|
||||
Get-ChocolateyConfig -choco_app $choco_app
|
||||
Get-ChocolateyFeature -choco_app $choco_app
|
||||
Get-ChocolateyPackages -choco_app $choco_app
|
||||
Get-ChocolateySources -choco_app $choco_app
|
||||
|
||||
# Return result
|
||||
Exit-Json -obj $result
|
139
lib/ansible/modules/windows/win_chocolatey_facts.py
Normal file
139
lib/ansible/modules/windows/win_chocolatey_facts.py
Normal file
|
@ -0,0 +1,139 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2018, Ansible Project
|
||||
# Copyright: (c) 2018, Simon Baerlocher <s.baerlocher@sbaerlocher.ch>
|
||||
# Copyright: (c) 2018, ITIGO AG <opensource@itigo.ch>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: win_chocolatey_facts
|
||||
version_added: '2.8'
|
||||
short_description: Create a facts collection for Chocolatey
|
||||
description:
|
||||
- This module shows information from Chocolatey, such as installed packages, configuration, feature and sources.
|
||||
author:
|
||||
- Simon Bärlocher (@sbaerlocher)
|
||||
- ITIGO AG (@itigoag)
|
||||
notes:
|
||||
- Chocolatey must be installed beforehand, use M(win_chocolatey) to do this.
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
- name: Gather facts from chocolatey
|
||||
win_chocolatey_facts:
|
||||
|
||||
- name: Displays the Configuration
|
||||
debug:
|
||||
var: ansible_chocolatey.config
|
||||
|
||||
- name: Displays the Feature
|
||||
debug:
|
||||
var: ansible_chocolatey.feature
|
||||
|
||||
- name: Displays the Sources
|
||||
debug:
|
||||
var: ansible_chocolatey.sources
|
||||
|
||||
- name: Displays the Packages
|
||||
debug:
|
||||
var: ansible_chocolatey.packages
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
ansible_facts:
|
||||
description: Detailed information about the Chocolatey installation
|
||||
returned: always
|
||||
type: complex
|
||||
contains:
|
||||
ansible_chocolatey:
|
||||
description: Detailed information about the Chocolatey installation
|
||||
returned: always
|
||||
type: complex
|
||||
contains:
|
||||
config:
|
||||
description: Detailed information about stored the configurations
|
||||
returned: always
|
||||
type: dict
|
||||
sample:
|
||||
commandExecutionTimeoutSeconds: 2700
|
||||
containsLegacyPackageInstalls: true
|
||||
feature:
|
||||
description: Detailed information about enabled and disabled features
|
||||
returned: always
|
||||
type: dict
|
||||
sample:
|
||||
allowEmptyCheckums: false
|
||||
autoUninstaller: true
|
||||
failOnAutoUninstaller: false
|
||||
sources:
|
||||
description: List of Chocolatey sources
|
||||
returned: always
|
||||
type: complex
|
||||
contains:
|
||||
admin_only:
|
||||
description: Is the source visible to Administrators only
|
||||
returned: always
|
||||
type: bool
|
||||
sample: false
|
||||
allow_self_service:
|
||||
description: Is the source allowed to be used with self-service
|
||||
returned: always
|
||||
type: bool
|
||||
sample: false
|
||||
bypass_proxy:
|
||||
description: Can the source explicitly bypass configured proxies
|
||||
returned: always
|
||||
type: bool
|
||||
sample: true
|
||||
certificate:
|
||||
description: Pth to a PFX certificate for X509 authenticated feeds
|
||||
returned: always
|
||||
type: string
|
||||
sample: C:\chocolatey\cert.pfx
|
||||
disabled:
|
||||
description: Is the source disabled
|
||||
returned: always
|
||||
type: bool
|
||||
sample: false
|
||||
name:
|
||||
description: Name of the source
|
||||
returned: always
|
||||
type: string
|
||||
sample: chocolatey
|
||||
priority:
|
||||
description: The priority order of this source, lower is better, 0 is no priority
|
||||
returned: always
|
||||
type: int
|
||||
sample: 0
|
||||
source:
|
||||
description: The source, can be a folder/file or an url
|
||||
returned: always
|
||||
type: string
|
||||
sample: https://chocolatey.org/api/v2/
|
||||
source_username:
|
||||
description: Username used to access authenticated feeds
|
||||
returned: always
|
||||
type: string
|
||||
sample: username
|
||||
packages:
|
||||
description: List of installed Packages
|
||||
returned: alway
|
||||
type: complex
|
||||
contains:
|
||||
package:
|
||||
description: Name of the package
|
||||
returned: always
|
||||
type: string
|
||||
sample: vscode
|
||||
version:
|
||||
description: Version of the package
|
||||
returned: always
|
||||
type: string
|
||||
sample: '1.27.2'
|
||||
'''
|
1
test/integration/targets/win_chocolatey_facts/aliases
Normal file
1
test/integration/targets/win_chocolatey_facts/aliases
Normal file
|
@ -0,0 +1 @@
|
|||
shippable/windows/group4
|
69
test/integration/targets/win_chocolatey_facts/tasks/main.yml
Normal file
69
test/integration/targets/win_chocolatey_facts/tasks/main.yml
Normal file
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
- name: ensure Chocolatey is installed
|
||||
win_chocolatey:
|
||||
name: chocolatey
|
||||
state: present
|
||||
|
||||
- name: create test source
|
||||
win_chocolatey_source:
|
||||
name: test|repo # use a pipe as that's a delimiter with Chocolatey, test edge case
|
||||
state: disabled
|
||||
admin_only: yes
|
||||
allow_self_service: yes
|
||||
bypass_proxy: yes
|
||||
priority: 9
|
||||
source: http://test-server/chocolatey
|
||||
source_username: test-user
|
||||
source_password: password
|
||||
certificate: C:\temp\cert.pfx
|
||||
|
||||
|
||||
- name: set a config value
|
||||
win_chocolatey_config:
|
||||
name: proxyUser
|
||||
state: present
|
||||
value: test-user
|
||||
|
||||
- block:
|
||||
- name: Gather facts from chocolatey
|
||||
win_chocolatey_facts:
|
||||
|
||||
always:
|
||||
- name: remove test source
|
||||
win_chocolatey_source:
|
||||
name: test|repo
|
||||
state: absent
|
||||
|
||||
- name: unset config value
|
||||
win_chocolatey_config:
|
||||
name: proxyUser
|
||||
state: absent
|
||||
|
||||
- name: assert facts from chocolatey
|
||||
assert:
|
||||
that:
|
||||
- ansible_chocolatey is not changed
|
||||
- ansible_chocolatey.config.commandExecutionTimeoutSeconds == 2700
|
||||
- ansible_chocolatey.config.proxyBypassOnLocal == True
|
||||
- ansible_chocolatey.config.proxyUser == 'test-user'
|
||||
- ansible_chocolatey.feature.checksumFiles == true
|
||||
- ansible_chocolatey.packages[0].package == 'chocolatey'
|
||||
- ansible_chocolatey.packages[0].version is defined
|
||||
- ansible_chocolatey.sources[0].admin_only == False
|
||||
- ansible_chocolatey.sources[0].allow_self_service == False
|
||||
- ansible_chocolatey.sources[0].bypass_proxy == False
|
||||
- ansible_chocolatey.sources[0].certificate == None
|
||||
- ansible_chocolatey.sources[0].disabled == False
|
||||
- ansible_chocolatey.sources[0].name == 'chocolatey'
|
||||
- ansible_chocolatey.sources[0].priority == 0
|
||||
- ansible_chocolatey.sources[0].source == 'https://chocolatey.org/api/v2/'
|
||||
- ansible_chocolatey.sources[0].source_username == None
|
||||
- ansible_chocolatey.sources[1].admin_only == True
|
||||
- ansible_chocolatey.sources[1].allow_self_service == True
|
||||
- ansible_chocolatey.sources[1].bypass_proxy == True
|
||||
- ansible_chocolatey.sources[1].certificate == 'C:\\temp\\cert.pfx'
|
||||
- ansible_chocolatey.sources[1].disabled == True
|
||||
- ansible_chocolatey.sources[1].name == 'test|repo'
|
||||
- ansible_chocolatey.sources[1].priority == 9
|
||||
- ansible_chocolatey.sources[1].source == 'http://test-server/chocolatey'
|
||||
- ansible_chocolatey.sources[1].source_username == 'test-user'
|
Loading…
Reference in a new issue