Skip to content

Commit

Permalink
Merge pull request #434 from JamesWTruher/apt001
Browse files Browse the repository at this point in the history
Create apt package management resource.
  • Loading branch information
SteveL-MSFT committed May 16, 2024
2 parents 1572460 + e28061b commit 06e79cd
Show file tree
Hide file tree
Showing 9 changed files with 302 additions and 1 deletion.
23 changes: 23 additions & 0 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ $filesForWindowsPackage = @(
$filesForLinuxPackage = @(
'dsc',
'assertion.dsc.resource.json',
'apt.dsc.resource.json',
'apt.dsc.resource.sh',
'group.dsc.resource.json',
'powershell.dsc.resource.json',
'psDscAdapter/',
Expand All @@ -64,6 +66,12 @@ $filesForMacPackage = @(
'runcommandonset'
)

# the list of files other than the binaries which need to be executable
$filesToBeExecutable = @(
'apt.dsc.resource.sh',
'brew.dsc.resource.sh'
)

function Find-LinkExe {
try {
# this helper may not be needed anymore, but keeping in case the install doesn't work for everyone
Expand Down Expand Up @@ -162,6 +170,7 @@ if (!$SkipBuild) {
$windows_projects = @("pal", "registry", "reboot_pending", "wmi-adapter")

$macOS_projects = @("resources/brew")
$linux_projects = @("resources/apt")

# projects are in dependency order
$projects = @(
Expand Down Expand Up @@ -192,6 +201,10 @@ if (!$SkipBuild) {
$projects += $macOS_projects
}

if ($IsLinux) {
$projects += $linux_projects
}

$failed = $false
foreach ($project in $projects) {
## Build format_json
Expand Down Expand Up @@ -255,6 +268,16 @@ if (!$SkipBuild) {

Copy-Item "*.dsc.resource.json" $target -Force -ErrorAction Ignore

# be sure that the files that should be executable are executable
if ($IsLinux -or $IsMacOS) {
foreach ($exeFile in $filesToBeExecutable) {
$exePath = "$target/$exeFile"
if (test-path $exePath) {
chmod +x $exePath
}
}
}

} finally {
Pop-Location
}
Expand Down
7 changes: 6 additions & 1 deletion dsc/tests/dsc_resource_list.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ Describe 'Tests for listing resources' {
}

It 'dsc resource list --tags "<tags>" and --description "<description> work' -TestCases @(
@{ tags = 'linux'; description = $null; expectedCount = 1; expectedType = 'Microsoft/OSInfo' }
if ($IsLinux) {
@{ tags = 'linux'; description = $null; expectedCount = 2; expectedType = @('DSC.PackageManagement/Apt', 'Microsoft/OSInfo') }
}
else {
@{ tags = 'linux'; description = $null; expectedCount = 1; expectedType = 'Microsoft/OSInfo' }
}
@{ tags = $null; description = 'operating system'; expectedCount = 1; expectedType = 'Microsoft/OSInfo' }
@{ tags = 'linux'; description = 'operating system'; expectedCount = 1; expectedType = 'Microsoft/OSInfo' }
@{ tags = 'notfound'; description = 'operating system'; expectedCount = 0; expectedType = $null }
Expand Down
74 changes: 74 additions & 0 deletions resources/apt/apt.dsc.resource.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"$schema": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/bundled/resource/manifest.json",
"type": "DSC.PackageManagement/Apt",
"description": "Manage packages with the advanced package tool (APT)",
"tags": [
"Linux",
"apt",
"PackageManagement"
],
"version": "0.1.0",
"get": {
"executable": "apt.dsc.resource.sh",
"args": [
"get"
],
"input": "env"
},
"set": {
"executable": "apt.dsc.resource.sh",
"args": [
"set"
],
"input": "env",
"implementsPretest": true,
"handlesExist": true
},
"export": {
"executable": "apt.dsc.resource.sh",
"args": [
"export"
],
"input": "env"
},
"exitCodes": {
"0": "Success",
"1": "Invalid parameter"
},
"schema": {
"embedded": {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/resources/DSC/PackageManagement/apt/v0.1.0/schema.json",
"title": "Apt",
"description": "Managed packages using apt",
"type": "object",
"required": [
"packageName"
],
"additionalProperties": false,
"properties": {
"packageName": {
"type": "string",
"title": "Package Name",
"description": "Defines the name of the package to query or install"
},
"version": {
"type": "string",
"title": "Version",
"description": "Defines the version of the package to install"
},
"source": {
"type": "string",
"title": "Source",
"description": "Indicates the source of the package",
"readOnly": true
},
"_exist": {
"type": "boolean",
"title": "Exist",
"description": "Defines if the package should exist or not"
}
}
}
}
}
61 changes: 61 additions & 0 deletions resources/apt/apt.dsc.resource.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/bin/bash

# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

export exist=true
export NONINTERACTIVE=1

# $packageName and $_exist are sent as env vars by dsc converting the JSON input to name/value pairs

check_args() {
if [[ -z $packageName ]]; then
echo "packageName not set"
exit 1
fi
}

get_apt() {
pkgname=$1
InstalledSection=0
apt list --installed $pkgname 2>&1 | while read line; do
if [[ $line == Listing* ]]; then
InstalledSection=1
elif [[ $InstalledSection = 1 ]]; then
echo $line | awk '{
split($0, a, " ");
split(a[1], pn, "/");
printf("{ \"_exist\": \"%s\", \"packageName\": \"%s\", \"version\": \"%s\", \"source\": \"%s\" }\n", ENVIRON["exist"], pn[1], a[2], pn[2]);
}'
fi
done
}

if [[ "$#" -eq "0" ]]; then
echo "Command not provided, valid commands: get, set, export"
exit 1
elif [[ "$1" == "get" ]]; then
check_args
output="$(get_apt $packageName)"
if [[ -z $output ]]; then
printf '{"_exist":"false","packageName":"%s","version":"","source":""}\n' $packageName
else
echo $output
fi
elif [[ "$1" == "set" ]]; then
check_args
if [[ -z $_exist ]]; then
# if $_exist is not defined in the input, it defaults to `true`
_exist=true
fi
if [[ $_exist = true ]]; then
apt install -y "${packageName}"
else
apt remove -y "${packageName}"
fi
elif [[ "$1" == "export" ]]; then
get_apt
else
echo "Invalid command, valid commands: get, set, export"
exit 1
fi
1 change: 1 addition & 0 deletions resources/apt/copy_files.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
apt.dsc.resource.sh
80 changes: 80 additions & 0 deletions resources/apt/test/apt.tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

Describe 'Apt resource tests' {
BeforeAll {
$aptExists = ($null -ne (Get-Command apt -CommandType Application -ErrorAction Ignore))
}

Context "export" {
It "should have more than 20 resources" -Skip:$(! $IsLinux) {
if (-not $aptExists) {
Set-ItResult -Skip -Because "Apt not found"
}

$result = dsc resource export --resource DSC.PackageManagement/Apt | ConvertFrom-Json
$result.resources.Count | Should -BeGreaterThan 20
}
}

Context "wget tests" {
BeforeAll {
$pkgName = "wget"
$yamlPath = "$PSScriptRoot/assets/apt_${pkgName}.dsc.yaml"
}

It 'Config get works' -Skip:$(! $IsLinux) {
if (-not $aptExists) {
Set-ItResult -Skip -Because "Apt not found"
}
$out = dsc config get -p $yamlPath | ConvertFrom-Json -Depth 10
$LASTEXITCODE | Should -Be 0
$exists = $null -ne (Get-Command $pkgName -CommandType Application -ErrorAction Ignore)
$observed = $out.results[1].result.actualState._exist
$observed | Should -Be $exists
}

It 'Config test works' -Skip:$(! $IsLinux) {
if (-not $aptExists) {
Set-ItResult -Skip -Because "Apt not found"
}

$out = dsc config test -p $yamlPath| ConvertFrom-Json -Depth 10
$LASTEXITCODE | Should -Be 0
$exists = $null -ne (Get-Command pkgName -CommandType Application -ErrorAction Ignore)
$out.results[1].result.inDesiredState | Should -Be $exists
}
}

Context "install/uninstall rolldice tests" {
BeforeAll {
$pkgName = "rolldice"
$yamlInstallPath = "$PSScriptRoot/assets/apt_install_${pkgName}.dsc.yaml"
$yamlUnInstallPath = "$PSScriptRoot/assets/apt_uninstall_${pkgName}.dsc.yaml"
}

It 'Can install a package' -Skip:$(! $IsLinux) {
Set-ItResult -Skip -Because "Apt requires sudo"

if (apt list $pkgname 2>&1 | Select-String installed ) {
apt remove -y $pkgname
}

$result = dsc config set -p $yamlInstallPath | ConvertFrom-Json
$result.results[1].result.beforestate._exist | Should -Be false
$result.results[1].result.afterstate._exist | Should -Be true
}

It 'Can uninstall a package' -Skip:$(! $IsLinux) {
Set-ItResult -Skip -Because "Apt requires sudo"

if ($null -eq (apt list $pkgName 2>&1 | Select-String installed)) {
apt install -y $pkgname
}

$result = dsc config set -p $yamlUnInstallPath | ConvertFrom-Json
$result.results[1].result.beforestate._exist | Should -Be true
$result.results[1].result.afterstate._exist | Should -Be false
}
}
}
19 changes: 19 additions & 0 deletions resources/apt/test/assets/apt_install_rolldice.dsc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Example to see if PowerShell 7 is installed, install it, or get all installed packages
$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json
resources:
- name: assertions
type: Microsoft.DSC/Assertion
properties:
$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json
resources:
- name: os_check
type: Microsoft/OSInfo
properties:
family: Linux
- name: apt_rolldice
type: DSC.PackageManagement/Apt
properties:
packageName: rolldice
_exist: true
dependsOn:
- "[resourceId('Microsoft.DSC/Assertion','assertions')]"
19 changes: 19 additions & 0 deletions resources/apt/test/assets/apt_uninstall_rolldice.dsc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Example to see if PowerShell 7 is installed, install it, or get all installed packages
$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json
resources:
- name: assertions
type: Microsoft.DSC/Assertion
properties:
$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json
resources:
- name: os_check
type: Microsoft/OSInfo
properties:
family: Linux
- name: apt_rolldice
type: DSC.PackageManagement/Apt
properties:
packageName: rolldice
_exist: false
dependsOn:
- "[resourceId('Microsoft.DSC/Assertion','assertions')]"
19 changes: 19 additions & 0 deletions resources/apt/test/assets/apt_wget.dsc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Example to see if PowerShell 7 is installed, install it, or get all installed packages
$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json
resources:
- name: assertions
type: Microsoft.DSC/Assertion
properties:
$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json
resources:
- name: os_check
type: Microsoft/OSInfo
properties:
family: Linux
- name: apt_wget
type: DSC.PackageManagement/Apt
properties:
packageName: wget
_exist: true
dependsOn:
- "[resourceId('Microsoft.DSC/Assertion','assertions')]"

0 comments on commit 06e79cd

Please sign in to comment.