Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c7511cb
Add SSH remoting CI
PaulHigin Mar 5, 2020
4000771
Fix typo
PaulHigin Mar 5, 2020
0db93ed
Add install git to Ubuntu CI
PaulHigin Mar 5, 2020
f628155
Update .vsts-ci/sshremoting-tests.yml
PaulHigin Mar 5, 2020
f27502e
Fix install git 1
PaulHigin Mar 5, 2020
2b75fd0
Add missing tools module import
PaulHigin Mar 5, 2020
b2b1854
Change ubuntu service restart
PaulHigin Mar 6, 2020
50f5e0c
Update ssh install
PaulHigin Mar 6, 2020
dbe66ed
fix module path
PaulHigin Mar 6, 2020
b1784ee
fix module path
PaulHigin Mar 6, 2020
466d732
change module import
PaulHigin Mar 6, 2020
ec235fc
Add tracing
PaulHigin Mar 6, 2020
2b80d1e
Add service start retry
PaulHigin Mar 6, 2020
c568afc
Fix service restart
PaulHigin Mar 6, 2020
83b00c5
Fix options restore
PaulHigin Mar 6, 2020
1d2e802
Fix Restore-PSOptions path
PaulHigin Mar 6, 2020
d5a5549
Fix Pester test output
PaulHigin Mar 6, 2020
04be24d
fix typo
PaulHigin Mar 6, 2020
5e2d471
Fix test output path
PaulHigin Mar 6, 2020
8318697
Debug 1
PaulHigin Mar 6, 2020
672fa26
Debug 2
PaulHigin Mar 7, 2020
b352329
Debug 3
PaulHigin Mar 7, 2020
7f8b2e7
Change results path
PaulHigin Mar 9, 2020
99cb598
Fix result publish to use build artifacts directory
PaulHigin Mar 9, 2020
b6faa0e
Add more New-PSSession tests
PaulHigin Mar 9, 2020
a9e6e1c
Remove User test
PaulHigin Mar 9, 2020
070b6ba
Remove env:USER
PaulHigin Mar 9, 2020
56d5fab
Add API tests
PaulHigin Mar 10, 2020
671c2ba
Fix type for Subsytem API test
PaulHigin Mar 10, 2020
7082e8c
Update .vsts-ci/sshremoting-tests.yml
PaulHigin Mar 10, 2020
c4a7bf4
Update .vsts-ci/sshremoting-tests.yml
PaulHigin Mar 10, 2020
704e849
Update .vsts-ci/sshremoting-tests.yml
PaulHigin Mar 10, 2020
4a3ebe3
Apply suggestions from code review
TravisEz13 Mar 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions .vsts-ci/sshremoting-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: PR-$(System.PullRequest.PullRequestNumber)-$(Date:yyyyMMdd)$(Rev:.rr)
trigger:
# Batch merge builds together while a merge build is running
batch: true
branches:
include:
- master
- release*
- feature*
paths:
include:
- '/src/System.Management.Automation/engine/*'
- '/test/SSHRemoting/*'
pr:
branches:
include:
- master
- release*
- feature*
paths:
include:
- '/src/System.Management.Automation/engine/*'
- '/test/SSHRemoting/*'

variables:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
POWERSHELL_TELEMETRY_OPTOUT: 1
# Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
__SuppressAnsiEscapeSequences: 1

resources:
- repo: self
clean: true
jobs:
- job: SSHRemotingTests
container: mcr.microsoft.com/powershell/test-deps:ubuntu-18.04
displayName: SSH Remoting Tests

steps:
- pwsh: |
Get-ChildItem -Path env:
displayName: Capture Environment
condition: succeededOrFailed()

- pwsh: Write-Host "##vso[build.updatebuildnumber]$env:BUILD_SOURCEBRANCHNAME-$env:BUILD_SOURCEVERSION-$((get-date).ToString("yyyyMMddhhmmss"))"
displayName: Set Build Name for Non-PR
condition: ne(variables['Build.Reason'], 'PullRequest')

- template: /tools/releaseBuild/azureDevOps/templates/insert-nuget-config-azfeed.yml

- pwsh: |
sudo apt-get update
sudo apt-get install -y git
displayName: Install Github
condition: succeeded()

- pwsh: |
Import-Module .\tools\ci.psm1
Invoke-CIInstall -SkipUser
displayName: Bootstrap
condition: succeededOrFailed()

- pwsh: |
Import-Module .\tools\ci.psm1
Invoke-CIBuild
displayName: Build
condition: succeeded()

- pwsh: |
Import-Module .\tools\ci.psm1
Restore-PSOptions
$options = (Get-PSOptions)
Import-Module .\test\tools\Modules\HelpersRemoting
Install-SSHRemoting -PowerShellFilePath $options.Output
displayName: Install SSH Remoting
condition: succeeded()

- pwsh: |
Import-Module .\tools\ci.psm1
Restore-PSOptions
$options = (Get-PSOptions)
Import-Module .\build.psm1
Start-PSPester -Path test/SSHRemoting -powershell $options.Output -OutputFile "$PWD/sshTestResults.xml"
displayName: Test
condition: succeeded()
7 changes: 6 additions & 1 deletion build.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -1364,7 +1364,12 @@ function Publish-TestResults
if($env:TF_BUILD)
{
$fileName = Split-Path -Leaf -Path $Path
$tempFilePath = Join-Path ([system.io.path]::GetTempPath()) -ChildPath $fileName
$tempPath = $env:BUILD_ARTIFACTSTAGINGDIRECTORY
if (! $tempPath)
{
$tempPath = [system.io.path]::GetTempPath()
}
$tempFilePath = Join-Path -Path $tempPath -ChildPath $fileName

# NUnit allowed values are: Passed, Failed, Inconclusive or Ignored (the spec says Skipped but it doesn' work with Azure DevOps)
# https://github.com/nunit/docs/wiki/Test-Result-XML-Format
Expand Down
187 changes: 187 additions & 0 deletions test/SSHRemoting/SSHRemoting.Basic.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

Describe "SSHRemoting Basic Tests" -tags CI {

# SSH remoting is set up to automatically authenticate current user via SSH keys
# All tests connect back to localhost machine

function VerifySession {
param (
[System.Management.Automation.Runspaces.PSSession] $session
)

$session.State | Should -BeExactly 'Opened'
$session.ComputerName | Should -BeExactly 'localhost'
$session.Transport | Should -BeExactly 'SSH'
Invoke-Command -Session $session -ScriptBlock { whoami } | Should -BeExactly $(whoami)
$psRemoteVersion = Invoke-Command -Session $session -ScriptBlock { $PSSenderInfo.ApplicationArguments.PSVersionTable.PSVersion }
$psRemoteVersion.Major | Should -BeExactly $PSVersionTable.PSVersion.Major
$psRemoteVersion.Minor | Should -BeExactly $PSVersionTable.PSVersion.Minor
}

Context "New-PSSession Tests" {

AfterEach {
if ($script:session -ne $null) { Remove-PSSession -session $script:session }
if ($script:sessions -ne $null) { Remove-PSSession -session $script:sessions }
}

It "Verifies new connection with implicit current User" {
$script:session = New-PSSession -HostName localhost -ErrorVariable err
$err | Should -HaveCount 0
VerifySession $script:session
}

It "Verifies new connection with explicit User parameter" {
$script:session = New-PSSession -HostName localhost -UserName (whoami) -ErrorVariable err
$err | Should -HaveCount 0
VerifySession $script:session
}

It "Verifies explicit Name parameter" {
$sessionName = 'TestSessionNameA'
$script:session = New-PSSession -HostName localhost -Name $sessionName -ErrorVariable err
$err | Should -HaveCount 0
VerifySession $script:session
$script:session.Name | Should -BeExactly $sessionName
}

It "Verifies explicit Port parameter" {
$portNum = 22
$script:session = New-PSSession -HostName localhost -Port $portNum -ErrorVariable err
$err | Should -HaveCount 0
VerifySession $script:session
}

It "Verifies explicit Subsystem parameter" {
$portNum = 22
$subSystem = 'powershell'
$script:session = New-PSSession -HostName localhost -Port $portNum -SubSystem $subSystem -ErrorVariable err
$err | Should -HaveCount 0
VerifySession $script:session
}

It "Verifies explicit KeyFilePath parameter" {
$keyFilePath = "$HOME/.ssh/id_rsa"
$portNum = 22
$subSystem = 'powershell'
$script:session = New-PSSession -HostName localhost -Port $portNum -SubSystem $subSystem -KeyFilePath $keyFilePath -ErrorVariable err
$err | Should -HaveCount 0
VerifySession $script:session
}

It "Verifies SSHConnection hash table parameters" {
$sshConnection = @(
@{
HostName = 'localhost'
UserName = whoami
Port = 22
KeyFilePath = "$HOME/.ssh/id_rsa"
Subsystem = 'powershell'
},
@{
HostName = 'localhost'
KeyFilePath = "$HOME/.ssh/id_rsa"
Subsystem = 'powershell'
})
$script:sessions = New-PSSession -SSHConnection $sshConnection -Name 'Connection1','Connection2' -ErrorVariable err
$err | Should -HaveCount 0
$script:sessions | Should -HaveCount 2
$script:sessions[0].Name | Should -BeLike 'Connection*'
$script:sessions[1].Name | Should -BeLike 'Connection*'
VerifySession $script:sessions[0]
VerifySession $script:sessions[1]
}
}

function VerifyRunspace {
param (
[runspace] $rs
)

$rs.RunspaceStateInfo.State | Should -BeExactly 'Opened'
$rs.RunspaceAvailability | Should -BeExactly 'Available'
$rs.RunspaceIsRemote | Should -BeTrue
$ps = [powershell]::Create()
try
{
$ps.Runspace = $rs
$psRemoteVersion = $ps.AddScript('$PSSenderInfo.ApplicationArguments.PSVersionTable.PSVersion').Invoke()
$psRemoteVersion.Major | Should -BeExactly $PSVersionTable.PSVersion.Major
$psRemoteVersion.Minor | Should -BeExactly $PSVersionTable.PSVersion.Minor

$ps.Commands.Clear()
$ps.AddScript('whoami').Invoke() | Should -BeExactly $(whoami)
}
finally
{
$ps.Dispose()
}
}

Context "SSH Remoting API Tests" {

AfterEach {
if ($script:rs -ne $null) { $script:rs.Dispose() }
}

$testCases = @(
@{
testName = 'Verifies connection with implicit user'
UserName = $null
ComputerName = 'localhost'
KeyFilePath = $null
Port = 0
Subsystem = $null
},
@{
testName = 'Verifies connection with UserName'
UserName = whoami
ComputerName = 'localhost'
KeyFilePath = $null
Port = 0
Subsystem = $null
},
@{
testName = 'Verifies connection with KeyFilePath'
UserName = whoami
ComputerName = 'localhost'
KeyFilePath = "$HOME/.ssh/id_rsa"
Port = 0
Subsystem = $null
},
@{
testName = 'Verifies connection with Port specified'
UserName = whoami
ComputerName = 'localhost'
KeyFilePath = "$HOME/.ssh/id_rsa"
Port = 22
Subsystem = $null
},
@{
testName = 'Verifies connection with Subsystem specified'
UserName = whoami
ComputerName = 'localhost'
KeyFilePath = "$HOME/.ssh/id_rsa"
Port = 22
Subsystem = 'powershell'
}
)

It "<testName>" -TestCases $testCases {
param (
$UserName,
$ComputerName,
$KeyFilePath,
$Port,
$SubSystem
)

$ci = [System.Management.Automation.Runspaces.SSHConnectionInfo]::new($UserName, $ComputerName, $KeyFilePath, $Port, $Subsystem)
$script:rs = [runspacefactory]::CreateRunspace($host, $ci)
$script:rs.Open()
VerifyRunspace $script:rs
}
}
}
59 changes: 55 additions & 4 deletions test/tools/Modules/HelpersRemoting/HelpersRemoting.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,26 @@ function Install-SSHRemotingOnWindows
}
}

function WriteVerboseSSHDStatus
{
param (
[string] $Msg = 'SSHD service status'
)

$sshdStatus = sudo service ssh status
Write-Verbose -Verbose "${Msg}: $sshdStatus"
}

function DumpTextFile
{
param (
[string] $FilePath = '/etc/ssh/sshd_config'
)

$content = Get-Content -Path $FilePath -Raw
Write-Verbose -Verbose $content
}

function Install-SSHRemotingOnLinux
{
param (
Expand All @@ -478,7 +498,11 @@ function Install-SSHRemotingOnLinux
{
Write-Verbose -Verbose "Installing openssh-server ..."
sudo apt-get install --yes openssh-server
sudo systemctl restart ssh

Write-Verbose -Verbose "Restarting sshd service after install ..."
WriteVerboseSSHDStatus "SSHD service status before restart"
sudo service ssh restart
WriteVerboseSSHDStatus "SSHD service status after restart"
}
if (! (Test-Path -Path /etc/ssh/sshd_config))
{
Expand Down Expand Up @@ -519,19 +543,40 @@ function Install-SSHRemotingOnLinux
Write-Verbose -Verbose "Updating known_hosts ..."
ssh-keyscan -H localhost | Set-Content -Path "$HOME/.ssh/known_hosts" -Force

<#
# Install Microsoft.PowerShell.RemotingTools module.
if ($null -eq (Get-Module -Name Microsoft.PowerShell.RemotingTools -ListAvailable))
{
Write-Verbose -Verbose "Installing Microsoft.PowerShell.RemotingTools ..."
Install-Module -Name Microsoft.PowerShell.RemotingTools -Force -SkipPublisherCheck
}
#>

# Add PowerShell endpoint to SSHD.
Write-Verbose -Verbose "Running Enable-SSHRemoting ..."
sudo pwsh -c 'Enable-SSHRemoting -SSHDConfigFilePath /etc/ssh/sshd_config -PowerShellFilePath $PowerShellPath -Force'

Write-Verbose -Verbose "PSScriptRoot: $PSScriptRoot"
$modulePath = "${PSScriptRoot}\..\Microsoft.PowerShell.RemotingTools\Microsoft.PowerShell.RemotingTools.psd1"
$cmdLine = "Import-Module ${modulePath}; Enable-SSHRemoting -SSHDConfigFilePath /etc/ssh/sshd_config -PowerShellFilePath $PowerShellPath -Force"
Write-Verbose -Verbose "CmdLine: $cmdLine"
sudo pwsh -c $cmdLine

# Restart SSHD service for changes to take effect.
Start-Sleep -Seconds 1
WriteVerboseSSHDStatus "SSHD service status before restart"
Write-Verbose -Verbose "Restarting sshd ..."
sudo systemctl restart ssh
sudo service ssh restart
WriteVerboseSSHDStatus "SSHD service status after restart"

# Try starting again if needed.
$status = sudo service ssh status
$result = $status | Where-Object { ($_ -like '*not running*') -or ($_ -like '*stopped*') }
if ($null -ne $result)
{
Start-Sleep -Seconds 1
Write-Verbose -Verbose "Starting sshd again ..."
sudo service ssh start
WriteVerboseSSHDStatus "SSHD service status after second start attempt"
}

# Test SSH remoting.
Write-Verbose -Verbose "Testing SSH remote connection ..."
Expand All @@ -542,6 +587,10 @@ function Install-SSHRemotingOnLinux
{
throw "Could not successfully create SSH remoting connection."
}
else
{
Write-Verbose -Verbose "SUCCESS: SSH remote connection"
}
}
finally
{
Expand Down Expand Up @@ -569,6 +618,8 @@ function Install-SSHRemoting
[string] $PowerShellFilePath
)

Write-Verbose -Verbose "Install-SSHRemoting called with PowerShell file path: $PowerShellFilePath"

if ($IsWindows)
{
if ([string]::IsNullOrEmpty($PowerShellFilePath)) { $PowerShellFilePath = "$PSHOME/pwsh.exe" }
Expand Down
Loading