Functions/Start-AnsibleControlNode.ps1
<#
.SYNOPSIS Start an ansible control node docker container. .DESCRIPTION This command is used to start a local docker container for the specific ansible repository. With this, an ansible control node under Windows is easy to use. .EXAMPLE PS C:\> Start-AnsibleControlNode Start the ansible control node with the current working directory. .EXAMPLE PS C:\> Start-AnsibleControlNode -RepositoryPath 'C:\Workspace\AnsibleRepo' -KeyPath 'C:\Workspace\AnsibleKeys' Start the ansible control node with custom repo and key path. .LINK https://github.com/claudiospizzi/PSAnsibleControlNode #> function Start-AnsibleControlNode { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low', DefaultParameterSetName = 'KeyPath')] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '')] param ( # Path to the ansible repository. Defaults to the current working directory. [Parameter(Mandatory = $false)] [System.String] $RepositoryPath = $PWD, # Path to the SSH key files. Defaults to the current user ~/.ssh path. [Parameter(Mandatory = $false, ParameterSetName = 'KeyPath')] [System.String] $KeyPath = "$HOME\.ssh", # Id of the 1Password ssh key item. Check with `op.exe item list` for all items. [Parameter(Mandatory = $false, ParameterSetName = '1Password')] [Alias('1PasswordItemId')] [System.String] $OPItemId = '', # Optionally specify a different item label for the 1Password public key. [Parameter(Mandatory = $false, ParameterSetName = '1Password')] [Alias('1PasswordItemPublicKeyLabel')] [System.String] $OPItemPublicKeyLabel = 'public key', # Optionally specify a different item label for the 1Password private key. [Parameter(Mandatory = $false, ParameterSetName = '1Password')] [Alias('1PasswordItemPrivateKeyLabel')] [System.String] $OPItemPrivateKeyLabel = 'private key', # Optionally specify a different item label for the 1Password key type. [Parameter(Mandatory = $false, ParameterSetName = '1Password')] [Alias('1PasswordItemKeyTypeLabel')] [System.String] $OPItemKeyTypeLabel = 'key type', # Docker image to use. Defaults to the claudiospizzi/ansible-control-node image. [Parameter(Mandatory = $false)] [System.String] $ImageName = 'claudiospizzi/ansible-control-node', # Tag of the docker ansible-control-node image. Defaults to the latest. [Parameter(Mandatory = $false)] [System.String] $ImageTag = 'latest', # Hide the user information. [Parameter(Mandatory = $false)] [Switch] $Silent ) try { # Specify the additional paths $ansibleConfigPath = '{0}\ansible.cfg' -f $RepositoryPath.TrimEnd('\').TrimEnd('/') # Check the ansible repository if (-not (Test-Path -Path $RepositoryPath)) { throw "The repository path was not found: $RepositoryPath" } if (-not (Test-Path -Path $ansibleConfigPath)) { throw "The ansible config file was not found: $ansibleConfigPath" } $RepositoryPath = (Resolve-Path -Path $RepositoryPath).Path # Check the SSH keys specified by path if ($PSCmdlet.ParameterSetName -eq 'KeyPath') { if (-not (Test-Path -Path $KeyPath)) { throw "The SSH key path was not found: $KeyPath" } if ($null -eq (Get-ChildItem -Path $KeyPath -Filter 'id_*')) { throw 'No certificate files matching the wildcard pattern id_* found.' } $KeyPath = (Resolve-Path -Path $KeyPath).Path } # Check the SSH keys specified by a 1Password item if ($PSCmdlet.ParameterSetName -eq '1Password') { # Ensure the command exists. Will throw an exception, if not. Get-Command -Name 'op.exe' | Out-Null $KeyPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath (New-Guid) New-Item -Path $KeyPath -ItemType 'Directory' | Out-Null $keyItem = op.exe item get $OPItemId --fields "label=$OPItemPublicKeyLabel,label=$OPItemPrivateKeyLabel,label=$OPItemKeyTypeLabel" --format json | ConvertFrom-Json # Get the key type, used for the key file name. $keyType = $keyItem.Where({ $_.label -eq $OPItemKeyTypeLabel }).value Set-Content -Path "$KeyPath\id_$keyType.pub" -Value $keyItem.Where({ $_.label -eq $OPItemPublicKeyLabel }).value -Encoding 'UTF8' Set-Content -Path "$KeyPath\id_$keyType" -Value $keyItem.Where({ $_.label -eq $OPItemPrivateKeyLabel }).value -Encoding 'UTF8' } # Check the docker desktop command if ($null -eq (Get-Command -Name 'docker.exe' -CommandType 'Application' -ErrorAction 'SilentlyContinue')) { throw 'The Docker executable docker.exe was not found in the path.' } if ($null -eq (Get-Process -Name 'Docker Desktop' -ErrorAction 'SilentlyContinue')) { throw 'The Docker Desktop process was not found. Start Docker Desktop.' } # Ensure the helper files and folders exist $acnFolderName = '.ansible-control-node' if (-not (Test-Path -Path "$RepositoryPath\$acnFolderName" -PathType 'Container')) { New-Item -Path "$RepositoryPath\$acnFolderName" -ItemType 'Directory' -Force | Out-Null } if (-not (Test-Path -Path "$RepositoryPath\$acnFolderName\.bash_history" -PathType 'Leaf')) { New-Item -Path "$RepositoryPath\$acnFolderName\.bash_history" -ItemType 'File' -Force | Out-Null } # Prepare the docker parameters $normalizedKeyPath = $KeyPath.Replace(':', '').Replace('\', '/').Trim('/') $normalizedRepoPath = $RepositoryPath.Replace(':', '').Replace('\', '/').Trim('/') $volumeKeys = '/{0}:/tmp/.ssh:ro' -f $normalizedKeyPath $volumeBashHistory = '/{0}/{1}/.bash_history:/root/.bash_history' -f $normalizedRepoPath, $acnFolderName $volumeAnsibleRepo = '/{0}:/ansible' -f $normalizedRepoPath $image = '{0}:{1}' -f $ImageName, $ImageTag # User information if (-not $Silent.IsPresent) { Write-Host '' Write-Host 'ANSIBLE CONTROL NODE' Write-Host '********************' Write-Host '' Write-Host "Ansible Repo: $RepositoryPath" Write-Host "SSH Key Path: $KeyPath$(if ($PSCmdlet.ParameterSetName -eq '1Password') { ' (removed in 10 sec)' })" Write-Host "Docker Image: $image" Write-Host '' } # Start the docker image if ($PSCmdlet.ShouldProcess($image, 'Start Docker Container')) { # Remove the 1Password key files after 10 seconds if ($PSCmdlet.ParameterSetName -eq '1Password') { Start-Job -ScriptBlock { Start-Sleep -Seconds 10 Remove-Item -Path $using:KeyPath -Force -Recurse } | Out-Null } docker.exe run -it --rm -v $volumeKeys -v $volumeBashHistory -v $volumeAnsibleRepo $image } } catch { $PSCmdlet.ThrowTerminatingError($_) } finally { # Remove the 1Password key files after closing the docker instance if ($PSCmdlet.ParameterSetName -eq '1Password' -and (Test-Path -Path $KeyPath)) { Remove-Item -Path $KeyPath -Force -Recurse } } } |