win test: add http tester container to Windows tests (#46606)
This commit is contained in:
parent
c44860057e
commit
6e2897647c
8 changed files with 353 additions and 7 deletions
|
@ -3,6 +3,11 @@
|
||||||
- set_fact:
|
- set_fact:
|
||||||
has_httptester: "{{ lookup('env', 'HTTPTESTER') != '' }}"
|
has_httptester: "{{ lookup('env', 'HTTPTESTER') != '' }}"
|
||||||
|
|
||||||
|
- name: make sure we have the ansible_os_family and ansible_distribution_version facts
|
||||||
|
setup:
|
||||||
|
gather_subset: distribution
|
||||||
|
when: ansible_facts == {}
|
||||||
|
|
||||||
# If we are running with access to a httptester container, grab it's cacert and install it
|
# If we are running with access to a httptester container, grab it's cacert and install it
|
||||||
- block:
|
- block:
|
||||||
# Override hostname defaults with httptester linked names
|
# Override hostname defaults with httptester linked names
|
||||||
|
@ -22,6 +27,16 @@
|
||||||
get_url:
|
get_url:
|
||||||
url: "http://ansible.http.tests/{{ item }}"
|
url: "http://ansible.http.tests/{{ item }}"
|
||||||
dest: "{{ output_dir }}/{{ item }}"
|
dest: "{{ output_dir }}/{{ item }}"
|
||||||
|
when: ansible_os_family != 'Windows'
|
||||||
|
with_items:
|
||||||
|
- client.pem
|
||||||
|
- client.key
|
||||||
|
|
||||||
|
- name: Windows - Get client cert/key
|
||||||
|
win_get_url:
|
||||||
|
url: http://ansible.http.tests/{{ item }}
|
||||||
|
dest: '{{ win_output_dir }}\{{ item }}'
|
||||||
|
when: ansible_os_family == 'Windows'
|
||||||
with_items:
|
with_items:
|
||||||
- client.pem
|
- client.pem
|
||||||
- client.key
|
- client.key
|
||||||
|
@ -38,6 +53,12 @@
|
||||||
dest: "/usr/local/share/ca-certificates/ansible.crt"
|
dest: "/usr/local/share/ca-certificates/ansible.crt"
|
||||||
when: ansible_os_family == 'Debian'
|
when: ansible_os_family == 'Debian'
|
||||||
|
|
||||||
|
- name: Windows - Retrieve test cacert
|
||||||
|
win_get_url:
|
||||||
|
url: http://ansible.http.tests/cacert.pem
|
||||||
|
dest: '{{ win_output_dir }}\cacert.pem'
|
||||||
|
when: ansible_os_family == 'Windows'
|
||||||
|
|
||||||
- name: Redhat - Update ca trust
|
- name: Redhat - Update ca trust
|
||||||
command: update-ca-trust extract
|
command: update-ca-trust extract
|
||||||
when: ansible_os_family == 'RedHat'
|
when: ansible_os_family == 'RedHat'
|
||||||
|
@ -46,6 +67,14 @@
|
||||||
command: update-ca-certificates
|
command: update-ca-certificates
|
||||||
when: ansible_os_family == 'Debian' or ansible_os_family == 'Suse'
|
when: ansible_os_family == 'Debian' or ansible_os_family == 'Suse'
|
||||||
|
|
||||||
|
- name: Windows - Update ca trust
|
||||||
|
win_certificate_store:
|
||||||
|
path: '{{ win_output_dir }}\cacert.pem'
|
||||||
|
state: present
|
||||||
|
store_location: LocalMachine
|
||||||
|
store_name: Root
|
||||||
|
when: ansible_os_family == 'Windows'
|
||||||
|
|
||||||
- name: FreeBSD - Retrieve test cacert
|
- name: FreeBSD - Retrieve test cacert
|
||||||
get_url:
|
get_url:
|
||||||
url: "http://ansible.http.tests/cacert.pem"
|
url: "http://ansible.http.tests/cacert.pem"
|
||||||
|
@ -68,4 +97,7 @@
|
||||||
command: /usr/local/opt/openssl/bin/c_rehash
|
command: /usr/local/opt/openssl/bin/c_rehash
|
||||||
when: ansible_os_family == 'Darwin'
|
when: ansible_os_family == 'Darwin'
|
||||||
|
|
||||||
when: has_httptester|bool
|
when:
|
||||||
|
- has_httptester|bool
|
||||||
|
# skip the setup if running on Windows Server 2008 as httptester is not available
|
||||||
|
- ansible_os_family != 'Windows' or (ansible_os_family == 'Windows' and not ansible_distribution_version.startswith("6.0."))
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
shippable/windows/group3
|
shippable/windows/group3
|
||||||
unstable
|
needs/httptester
|
||||||
skip/windows/2008 # httptester requires SSH which doesn't work with 2008
|
skip/windows/2008 # httptester requires SSH which doesn't work with 2008
|
||||||
|
|
|
@ -1,3 +1,2 @@
|
||||||
---
|
---
|
||||||
test_uri_path: C:\ansible\win_uri
|
test_uri_path: '{{ win_output_dir }}\win_uri'
|
||||||
httpbin_host: httpbin.org
|
|
||||||
|
|
3
test/integration/targets/win_uri/meta/main.yml
Normal file
3
test/integration/targets/win_uri/meta/main.yml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
dependencies:
|
||||||
|
- prepare_win_tests
|
||||||
|
- prepare_http_tests
|
|
@ -333,6 +333,7 @@ def parse_args():
|
||||||
config=WindowsIntegrationConfig)
|
config=WindowsIntegrationConfig)
|
||||||
|
|
||||||
add_extra_docker_options(windows_integration, integration=False)
|
add_extra_docker_options(windows_integration, integration=False)
|
||||||
|
add_httptester_options(windows_integration, argparse)
|
||||||
|
|
||||||
windows_integration.add_argument('--windows',
|
windows_integration.add_argument('--windows',
|
||||||
metavar='VERSION',
|
metavar='VERSION',
|
||||||
|
|
|
@ -60,6 +60,8 @@ from lib.util import (
|
||||||
from lib.docker_util import (
|
from lib.docker_util import (
|
||||||
docker_pull,
|
docker_pull,
|
||||||
docker_run,
|
docker_run,
|
||||||
|
docker_available,
|
||||||
|
docker_rm,
|
||||||
get_docker_container_id,
|
get_docker_container_id,
|
||||||
get_docker_container_ip,
|
get_docker_container_ip,
|
||||||
)
|
)
|
||||||
|
@ -507,6 +509,8 @@ def command_windows_integration(args):
|
||||||
all_targets = tuple(walk_windows_integration_targets(include_hidden=True))
|
all_targets = tuple(walk_windows_integration_targets(include_hidden=True))
|
||||||
internal_targets = command_integration_filter(args, all_targets, init_callback=windows_init)
|
internal_targets = command_integration_filter(args, all_targets, init_callback=windows_init)
|
||||||
instances = [] # type: list [lib.thread.WrappedThread]
|
instances = [] # type: list [lib.thread.WrappedThread]
|
||||||
|
use_httptester = False
|
||||||
|
httptester_id = None
|
||||||
|
|
||||||
if args.windows:
|
if args.windows:
|
||||||
get_coverage_path(args) # initialize before starting threads
|
get_coverage_path(args) # initialize before starting threads
|
||||||
|
@ -533,12 +537,58 @@ def command_windows_integration(args):
|
||||||
with open(filename, 'w') as inventory_fd:
|
with open(filename, 'w') as inventory_fd:
|
||||||
inventory_fd.write(inventory)
|
inventory_fd.write(inventory)
|
||||||
|
|
||||||
|
use_httptester = args.httptester and any('needs/httptester/' in t.aliases for t in internal_targets)
|
||||||
|
# if running under Docker delegation, the httptester may have already been started
|
||||||
|
docker_httptester = bool(os.environ.get("HTTPTESTER", False))
|
||||||
|
|
||||||
|
if use_httptester and not docker_available() and not docker_httptester:
|
||||||
|
display.warning('Assuming --disable-httptester since `docker` is not available.')
|
||||||
|
use_httptester = False
|
||||||
|
|
||||||
|
if use_httptester:
|
||||||
|
if docker_httptester:
|
||||||
|
# we are running in a Docker container that is linked to the httptester container, we just need to
|
||||||
|
# forward these requests to the linked hostname
|
||||||
|
first_host = HTTPTESTER_HOSTS[0]
|
||||||
|
ssh_options = ["-R", "8080:%s:80" % first_host, "-R", "8443:%s:443" % first_host]
|
||||||
|
else:
|
||||||
|
# we are running directly and need to start the httptester container ourselves and forward the port
|
||||||
|
# from there manually set so HTTPTESTER env var is set during the run
|
||||||
|
args.inject_httptester = True
|
||||||
|
httptester_id, ssh_options = start_httptester(args)
|
||||||
|
|
||||||
|
# to get this SSH command to run in the background we need to set to run in background (-f) and disable
|
||||||
|
# the pty allocation (-T)
|
||||||
|
ssh_options.insert(0, "-fT")
|
||||||
|
|
||||||
|
# create a script that will continue to run in the background until the script is deleted, this will
|
||||||
|
# cleanup and close the connection
|
||||||
|
watcher_path = "ansible-test-http-watcher-%s.ps1" % time.time()
|
||||||
|
for remote in [r for r in remotes if r.version != '2008']:
|
||||||
|
manage = ManageWindowsCI(remote)
|
||||||
|
manage.upload("test/runner/setup/windows-httptester.ps1", watcher_path)
|
||||||
|
|
||||||
|
# need to use -Command as we cannot pass an array of values with -File
|
||||||
|
script = "powershell.exe -NoProfile -Command .\\%s -Hosts %s" % (watcher_path, ", ".join(HTTPTESTER_HOSTS))
|
||||||
|
if args.verbosity > 3:
|
||||||
|
script += " -Verbose"
|
||||||
|
manage.ssh(script, options=ssh_options, force_pty=False)
|
||||||
|
|
||||||
success = False
|
success = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
command_integration_filtered(args, internal_targets, all_targets)
|
command_integration_filtered(args, internal_targets, all_targets)
|
||||||
success = True
|
success = True
|
||||||
finally:
|
finally:
|
||||||
|
if use_httptester:
|
||||||
|
if httptester_id:
|
||||||
|
docker_rm(args, httptester_id)
|
||||||
|
|
||||||
|
for remote in [r for r in remotes if r.version != '2008']:
|
||||||
|
# delete the tmp file that keeps the http-tester alive
|
||||||
|
manage = ManageWindowsCI(remote)
|
||||||
|
manage.ssh("del %s /F /Q" % watcher_path)
|
||||||
|
|
||||||
if args.remote_terminate == 'always' or (args.remote_terminate == 'success' and success):
|
if args.remote_terminate == 'always' or (args.remote_terminate == 'success' and success):
|
||||||
for instance in instances:
|
for instance in instances:
|
||||||
instance.result.stop()
|
instance.result.stop()
|
||||||
|
@ -736,7 +786,8 @@ def command_integration_filtered(args, targets, all_targets):
|
||||||
display.warning('SSH service not responding. Waiting %d second(s) before checking again.' % seconds)
|
display.warning('SSH service not responding. Waiting %d second(s) before checking again.' % seconds)
|
||||||
time.sleep(seconds)
|
time.sleep(seconds)
|
||||||
|
|
||||||
if args.inject_httptester:
|
# Windows is different as Ansible execution is done locally but the host is remote
|
||||||
|
if args.inject_httptester and not isinstance(args, WindowsIntegrationConfig):
|
||||||
inject_httptester(args)
|
inject_httptester(args)
|
||||||
|
|
||||||
start_at_task = args.start_at_task
|
start_at_task = args.start_at_task
|
||||||
|
|
|
@ -75,24 +75,57 @@ class ManageWindowsCI(object):
|
||||||
raise ApplicationError('Timeout waiting for %s/%s instance %s.' %
|
raise ApplicationError('Timeout waiting for %s/%s instance %s.' %
|
||||||
(self.core_ci.platform, self.core_ci.version, self.core_ci.instance_id))
|
(self.core_ci.platform, self.core_ci.version, self.core_ci.instance_id))
|
||||||
|
|
||||||
def ssh(self, command, options=None):
|
def download(self, remote, local):
|
||||||
|
"""
|
||||||
|
:type remote: str
|
||||||
|
:type local: str
|
||||||
|
"""
|
||||||
|
self.scp('%s@%s:%s' % (self.core_ci.connection.username, self.core_ci.connection.hostname, remote), local)
|
||||||
|
|
||||||
|
def upload(self, local, remote):
|
||||||
|
"""
|
||||||
|
:type local: str
|
||||||
|
:type remote: str
|
||||||
|
"""
|
||||||
|
self.scp(local, '%s@%s:%s' % (self.core_ci.connection.username, self.core_ci.connection.hostname, remote))
|
||||||
|
|
||||||
|
def ssh(self, command, options=None, force_pty=True):
|
||||||
"""
|
"""
|
||||||
:type command: str | list[str]
|
:type command: str | list[str]
|
||||||
:type options: list[str] | None
|
:type options: list[str] | None
|
||||||
|
:type force_pty: bool
|
||||||
"""
|
"""
|
||||||
if not options:
|
if not options:
|
||||||
options = []
|
options = []
|
||||||
|
if force_pty:
|
||||||
|
options.append('-tt')
|
||||||
|
|
||||||
if isinstance(command, list):
|
if isinstance(command, list):
|
||||||
command = ' '.join(pipes.quote(c) for c in command)
|
command = ' '.join(pipes.quote(c) for c in command)
|
||||||
|
|
||||||
run_command(self.core_ci.args,
|
run_command(self.core_ci.args,
|
||||||
['ssh', '-tt', '-q'] + self.ssh_args +
|
['ssh', '-q'] + self.ssh_args +
|
||||||
options +
|
options +
|
||||||
['-p', '22',
|
['-p', '22',
|
||||||
'%s@%s' % (self.core_ci.connection.username, self.core_ci.connection.hostname)] +
|
'%s@%s' % (self.core_ci.connection.username, self.core_ci.connection.hostname)] +
|
||||||
[command])
|
[command])
|
||||||
|
|
||||||
|
def scp(self, src, dst):
|
||||||
|
"""
|
||||||
|
:type src: str
|
||||||
|
:type dst: str
|
||||||
|
"""
|
||||||
|
for dummy in range(1, 10):
|
||||||
|
try:
|
||||||
|
run_command(self.core_ci.args,
|
||||||
|
['scp'] + self.ssh_args +
|
||||||
|
['-P', '22', '-q', '-r', src, dst])
|
||||||
|
return
|
||||||
|
except SubprocessError:
|
||||||
|
time.sleep(10)
|
||||||
|
|
||||||
|
raise ApplicationError('Failed transfer: %s -> %s' % (src, dst))
|
||||||
|
|
||||||
|
|
||||||
class ManageNetworkCI(object):
|
class ManageNetworkCI(object):
|
||||||
"""Manage access to a network instance provided by Ansible Core CI."""
|
"""Manage access to a network instance provided by Ansible Core CI."""
|
||||||
|
|
227
test/runner/setup/windows-httptester.ps1
Normal file
227
test/runner/setup/windows-httptester.ps1
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Designed to set a Windows host to connect to the httptester container running
|
||||||
|
on the Ansible host. This will setup the Windows host file and forward the
|
||||||
|
local ports to use this connection. This will continue to run in the background
|
||||||
|
until the script is deleted.
|
||||||
|
|
||||||
|
Run this with SSH with the -R arguments to foward ports 8080 and 8443 to the
|
||||||
|
httptester container.
|
||||||
|
|
||||||
|
.PARAMETER Hosts
|
||||||
|
A list of hostnames to add to the Windows hosts file for the httptester
|
||||||
|
container.
|
||||||
|
#>
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true, Position=0)][String[]]$Hosts
|
||||||
|
)
|
||||||
|
|
||||||
|
$ProgressPreference = "SilentlyContinue"
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
$os_version = [Version](Get-Item -Path "$env:SystemRoot\System32\kernel32.dll").VersionInfo.ProductVersion
|
||||||
|
Write-Verbose -Message "Configuring HTTP Tester on Windows $os_version for '$($Hosts -join "', '")'"
|
||||||
|
|
||||||
|
Function Get-PmapperRuleBytes {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Create the byte values that configures a rule in the PMapper configuration
|
||||||
|
file. This isn't really documented but because PMapper is only used for
|
||||||
|
Server 2008 R2 we will stick to 1 version and just live with the legacy
|
||||||
|
work for now.
|
||||||
|
|
||||||
|
.PARAMETER ListenPort
|
||||||
|
The port to listen on localhost, this will be forwarded to the host defined
|
||||||
|
by ConnectAddress and ConnectPort.
|
||||||
|
|
||||||
|
.PARAMETER ConnectAddress
|
||||||
|
The hostname or IP to map the traffic to.
|
||||||
|
|
||||||
|
.PARAMETER ConnectPort
|
||||||
|
This port of ConnectAddress to map the traffic to.
|
||||||
|
#>
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)][UInt16]$ListenPort,
|
||||||
|
[Parameter(Mandatory=$true)][String]$ConnectAddress,
|
||||||
|
[Parameter(Mandatory=$true)][Int]$ConnectPort
|
||||||
|
)
|
||||||
|
|
||||||
|
$connect_field = "$($ConnectAddress):$ConnectPort"
|
||||||
|
$connect_bytes = [System.Text.Encoding]::ASCII.GetBytes($connect_field)
|
||||||
|
$data_length = [byte]($connect_bytes.Length + 6) # size of payload minus header, length, and footer
|
||||||
|
$port_bytes = [System.BitConverter]::GetBytes($ListenPort)
|
||||||
|
|
||||||
|
$payload = [System.Collections.Generic.List`1[Byte]]@()
|
||||||
|
$payload.Add([byte]16) > $null # header is \x10, means Configure Mapping rule
|
||||||
|
$payload.Add($data_length) > $null
|
||||||
|
$payload.AddRange($connect_bytes)
|
||||||
|
$payload.AddRange($port_bytes)
|
||||||
|
$payload.AddRange([byte[]]@(0, 0)) # 2 extra bytes of padding
|
||||||
|
$payload.Add([byte]0) > $null # 0 is TCP, 1 is UDP
|
||||||
|
$payload.Add([byte]0) > $null # 0 is Any, 1 is Internet
|
||||||
|
$payload.Add([byte]31) > $null # footer is \x1f, means end of Configure Mapping rule
|
||||||
|
|
||||||
|
return ,$payload.ToArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Verbose -Message "Adding host file entries"
|
||||||
|
$hosts_file = "$env:SystemRoot\System32\drivers\etc\hosts"
|
||||||
|
$hosts_file_lines = [System.IO.File]::ReadAllLines($hosts_file)
|
||||||
|
$changed = $false
|
||||||
|
foreach ($httptester_host in $Hosts) {
|
||||||
|
$host_line = "127.0.0.1 $httptester_host # ansible-test httptester"
|
||||||
|
if ($host_line -notin $hosts_file_lines) {
|
||||||
|
$hosts_file_lines += $host_line
|
||||||
|
$changed = $true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($changed) {
|
||||||
|
Write-Verbose -Message "Host file is missing entries, adding missing entries"
|
||||||
|
[System.IO.File]::WriteAllLines($hosts_file, $hosts_file_lines)
|
||||||
|
}
|
||||||
|
|
||||||
|
# forward ports
|
||||||
|
$forwarded_ports = @{
|
||||||
|
80 = 8080
|
||||||
|
443 = 8443
|
||||||
|
}
|
||||||
|
if ($os_version -ge [Version]"6.2") {
|
||||||
|
Write-Verbose -Message "Using netsh to configure forwarded ports"
|
||||||
|
foreach ($forwarded_port in $forwarded_ports.GetEnumerator()) {
|
||||||
|
$port_set = netsh interface portproxy show v4tov4 | `
|
||||||
|
Where-Object { $_ -match "127.0.0.1\s*$($forwarded_port.Key)\s*127.0.0.1\s*$($forwarded_port.Value)" }
|
||||||
|
|
||||||
|
if (-not $port_set) {
|
||||||
|
Write-Verbose -Message "Adding netsh portproxy rule for $($forwarded_port.Key) -> $($forwarded_port.Value)"
|
||||||
|
$add_args = @(
|
||||||
|
"interface",
|
||||||
|
"portproxy",
|
||||||
|
"add",
|
||||||
|
"v4tov4",
|
||||||
|
"listenaddress=127.0.0.1",
|
||||||
|
"listenport=$($forwarded_port.Key)",
|
||||||
|
"connectaddress=127.0.0.1",
|
||||||
|
"connectport=$($forwarded_port.Value)"
|
||||||
|
)
|
||||||
|
$null = netsh $add_args 2>&1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Verbose -Message "Using Port Mapper to configure forwarded ports"
|
||||||
|
# netsh interface portproxy doesn't work on local addresses in older
|
||||||
|
# versions of Windows. Use custom application Port Mapper to acheive the
|
||||||
|
# same outcome
|
||||||
|
# http://www.analogx.com/contents/download/Network/pmapper/Freeware.htm
|
||||||
|
$s3_url = "https://s3.amazonaws.com/ansible-ci-files/ansible-test/pmapper-1.04.exe"
|
||||||
|
|
||||||
|
# download the Port Mapper executable to a temporary directory
|
||||||
|
$pmapper_folder = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ([System.IO.Path]::GetRandomFileName())
|
||||||
|
$pmapper_exe = Join-Path -Path $pmapper_folder -ChildPath pmapper.exe
|
||||||
|
$pmapper_config = Join-Path -Path $pmapper_folder -ChildPath pmapper.dat
|
||||||
|
New-Item -Path $pmapper_folder -ItemType Directory > $null
|
||||||
|
|
||||||
|
$stop = $false
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
Write-Verbose -Message "Attempting download of '$s3_url'"
|
||||||
|
(New-Object -TypeName System.Net.WebClient).DownloadFile($s3_url, $pmapper_exe)
|
||||||
|
$stop = $true
|
||||||
|
} catch { Start-Sleep -Second 5 }
|
||||||
|
} until ($stop)
|
||||||
|
|
||||||
|
# create the Port Mapper rule file that contains our forwarded ports
|
||||||
|
$fs = [System.IO.File]::Create($pmapper_config)
|
||||||
|
try {
|
||||||
|
foreach ($forwarded_port in $forwarded_ports.GetEnumerator()) {
|
||||||
|
Write-Verbose -Message "Creating forwarded port rule for $($forwarded_port.Key) -> $($forwarded_port.Value)"
|
||||||
|
$pmapper_rule = Get-PmapperRuleBytes -ListenPort $forwarded_port.Key -ConnectAddress 127.0.0.1 -ConnectPort $forwarded_port.Value
|
||||||
|
$fs.Write($pmapper_rule, 0, $pmapper_rule.Length)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
$fs.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Verbose -Message "Starting Port Mapper '$pmapper_exe' in the background"
|
||||||
|
$start_args = @{
|
||||||
|
CommandLine = $pmapper_exe
|
||||||
|
CurrentDirectory = $pmapper_folder
|
||||||
|
}
|
||||||
|
$res = Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments $start_args
|
||||||
|
if ($res.ReturnValue -ne 0) {
|
||||||
|
$error_msg = switch($res.ReturnValue) {
|
||||||
|
2 { "Access denied" }
|
||||||
|
3 { "Insufficient privilege" }
|
||||||
|
8 { "Unknown failure" }
|
||||||
|
9 { "Path not found" }
|
||||||
|
21 { "Invalid parameter" }
|
||||||
|
default { "Undefined Error: $($res.ReturnValue)" }
|
||||||
|
}
|
||||||
|
Write-Error -Message "Failed to start pmapper: $error_msg"
|
||||||
|
}
|
||||||
|
$pmapper_pid = $res.ProcessId
|
||||||
|
Write-Verbose -Message "Port Mapper PID: $pmapper_pid"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Verbose -Message "Wait for current script at '$PSCommandPath' to be deleted before running cleanup"
|
||||||
|
$fsw = New-Object -TypeName System.IO.FileSystemWatcher
|
||||||
|
$fsw.Path = Split-Path -Path $PSCommandPath -Parent
|
||||||
|
$fsw.Filter = Split-Path -Path $PSCommandPath -Leaf
|
||||||
|
$fsw.WaitForChanged([System.IO.WatcherChangeTypes]::Deleted, 3600000) > $null
|
||||||
|
Write-Verbose -Message "Script delete or timeout reached, cleaning up Windows httptester artifacts"
|
||||||
|
|
||||||
|
Write-Verbose -Message "Cleanup host file entries"
|
||||||
|
$hosts_file_lines = [System.IO.File]::ReadAllLines($hosts_file)
|
||||||
|
$new_lines = [System.Collections.ArrayList]@()
|
||||||
|
$changed = $false
|
||||||
|
foreach ($host_line in $hosts_file_lines) {
|
||||||
|
if ($host_line.EndsWith("# ansible-test httptester")) {
|
||||||
|
$changed = $true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
$new_lines.Add($host_line) > $null
|
||||||
|
}
|
||||||
|
if ($changed) {
|
||||||
|
Write-Verbose -Message "Host file has extra entries, removing extra entries"
|
||||||
|
[System.IO.File]::WriteAllLines($hosts_file, $new_lines)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($os_version -ge [Version]"6.2") {
|
||||||
|
Write-Verbose -Message "Cleanup of forwarded port configured in netsh"
|
||||||
|
foreach ($forwarded_port in $forwarded_ports.GetEnumerator()) {
|
||||||
|
$port_set = netsh interface portproxy show v4tov4 | `
|
||||||
|
Where-Object { $_ -match "127.0.0.1\s*$($forwarded_port.Key)\s*127.0.0.1\s*$($forwarded_port.Value)" }
|
||||||
|
|
||||||
|
if ($port_set) {
|
||||||
|
Write-Verbose -Message "Removing netsh portproxy rule for $($forwarded_port.Key) -> $($forwarded_port.Value)"
|
||||||
|
$delete_args = @(
|
||||||
|
"interface",
|
||||||
|
"portproxy",
|
||||||
|
"delete",
|
||||||
|
"v4tov4",
|
||||||
|
"listenaddress=127.0.0.1",
|
||||||
|
"listenport=$($forwarded_port.Key)"
|
||||||
|
)
|
||||||
|
$null = netsh $delete_args 2>&1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Verbose -Message "Stopping Port Mapper executable based on pid $pmapper_pid"
|
||||||
|
Stop-Process -Id $pmapper_pid -Force
|
||||||
|
|
||||||
|
# the process may not stop straight away, try multiple times to delete the Port Mapper folder
|
||||||
|
$attempts = 1
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
Write-Verbose -Message "Cleanup temporary files for Port Mapper at '$pmapper_folder' - Attempt: $attempts"
|
||||||
|
Remove-Item -Path $pmapper_folder -Force -Recurse
|
||||||
|
break
|
||||||
|
} catch {
|
||||||
|
Write-Verbose -Message "Cleanup temporary files for Port Mapper failed, waiting 5 seconds before trying again:$($_ | Out-String)"
|
||||||
|
if ($attempts -ge 5) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
$attempts += 1
|
||||||
|
Start-Sleep -Second 5
|
||||||
|
}
|
||||||
|
} until ($true)
|
||||||
|
}
|
Loading…
Reference in a new issue