diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000000..0905e52204a --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +# https://docs.docker.com/engine/reference/builder/#dockerignore-file +# Exclude files not relevant to the build +# This helps to avoid unnecessarily sending large or sensitive files and directories to Docker daemon + +# Ignore everything and use Docker volumes +* diff --git a/.gitignore b/.gitignore index a79f8547f45..e7acbd3536e 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ syntax: glob # Tool Runtime Dir /[Tt]ools/ .dotnet/ +.dotnet-linux/ # User-specific files *.suo @@ -14,6 +15,7 @@ syntax: glob # Build results artifacts/ +artifacts-linux/ .idea/ [Dd]ebug/ [Dd]ebugPublic/ @@ -279,4 +281,4 @@ config.ps1 # Debug files *.etl -*.dmp \ No newline at end of file +*.dmp diff --git a/Docker/Client/Linux.dockerfile b/Docker/Client/Linux.dockerfile new file mode 100644 index 00000000000..f120ee49e97 --- /dev/null +++ b/Docker/Client/Linux.dockerfile @@ -0,0 +1,9 @@ +# Linux Docker image - Host WCF Client +FROM mcr.microsoft.com/dotnet/sdk:6.0.300-focal-amd64 + +# Run commands: +# Setup environment variables +# Install Root certificate +# Run WCF Tests +CMD /wcf/src/System.Private.ServiceModel/tools/scripts/SetClientEnv-Linux.sh && /wcf/src/System.Private.ServiceModel/tools/scripts/InstallRootCertificate.sh --cert-file /tmp/wcfrootca.crt && /wcf/eng/common/cibuild.sh -configuration Release --prepareMachine --ci --test --integrationTest + diff --git a/Docker/Client/Windows.dockerfile b/Docker/Client/Windows.dockerfile new file mode 100644 index 00000000000..809c7bc0815 --- /dev/null +++ b/Docker/Client/Windows.dockerfile @@ -0,0 +1,12 @@ +# Windows Docker image - Host WCF Client +FROM mcr.microsoft.com/dotnet/framework/sdk:4.8 + +# Set Powershell as default Container shell +SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'Continue'; $verbosePreference='Continue';"] + +# Run commands: +# Setup environment variables +# Run WCF Tests +CMD C:\wcf\src\System.Private.ServiceModel\tools\scripts\SetClientEnv-Windows.cmd; C:\wcf\eng\common\cibuild.cmd -configuration Release -prepareMachine /p:Restore=true /p:Sign=false /p:Test=true /p:IntegrationTest=true /p:Pack=false /p:Publish=false; + + diff --git a/Docker/Service/Dockerfile b/Docker/Service/Dockerfile new file mode 100644 index 00000000000..1549a87b88b --- /dev/null +++ b/Docker/Service/Dockerfile @@ -0,0 +1,19 @@ +# Windows Docker image - Host WCF Service +FROM mcr.microsoft.com/dotnet/framework/wcf + +# Open IIS Hosted ports +EXPOSE 80 808 443 44345 + +# Open Self Hosted ports +EXPOSE 8081 8083 8084 44285 809 + +# Set Powershell as default Container shell +SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'Continue'; $verbosePreference='Continue';"] + +# Set ENTRYPOINT to Powershell +# Keeps the Service Container always running +ENTRYPOINT ["powershell"] + +# Container Startup command: +# Setup WCF IIS Hosted and Self Hosted Services, using Docker Volume at C:\wcf +CMD ./wcf/src/System.Private.ServiceModel/tools/scripts/SetupWcfIISHostedService.cmd 38 /p:"c:\wcf"; ./wcf/src/System.Private.ServiceModel/tools/scripts/StartWCFSelfHostedSvc.cmd; powershell diff --git a/src/System.Private.ServiceModel/tools/CertificateGenerator/App.config b/src/System.Private.ServiceModel/tools/CertificateGenerator/App.config index 970aad0e744..02dcadb10ac 100644 --- a/src/System.Private.ServiceModel/tools/CertificateGenerator/App.config +++ b/src/System.Private.ServiceModel/tools/CertificateGenerator/App.config @@ -6,6 +6,6 @@ - + diff --git a/src/System.Private.ServiceModel/tools/CertificateGenerator/CertificateGenerator.csproj b/src/System.Private.ServiceModel/tools/CertificateGenerator/CertificateGenerator.csproj index 8f7a07e652f..c0731816319 100644 --- a/src/System.Private.ServiceModel/tools/CertificateGenerator/CertificateGenerator.csproj +++ b/src/System.Private.ServiceModel/tools/CertificateGenerator/CertificateGenerator.csproj @@ -4,14 +4,14 @@ Exe CertificateGenerator CertificateGenerator - v4.5 + v4.8 - + - + diff --git a/src/System.Private.ServiceModel/tools/scripts/BuildSource.cmd b/src/System.Private.ServiceModel/tools/scripts/BuildSource.cmd new file mode 100644 index 00000000000..38247e6e38f --- /dev/null +++ b/src/System.Private.ServiceModel/tools/scripts/BuildSource.cmd @@ -0,0 +1,7 @@ +:: Build tools on Docker host machine. +:: This saves time during container startup and running tests (simply mount a volume for the build artifacts) + +:: Build certifcate generator tool +call BuildCertUtil.cmd +:: Build Self Hosted service +call BuildWCFSelfHostedService.cmd diff --git a/src/System.Private.ServiceModel/tools/scripts/BuildTest.cmd b/src/System.Private.ServiceModel/tools/scripts/BuildTest.cmd new file mode 100644 index 00000000000..c66f8a028b8 --- /dev/null +++ b/src/System.Private.ServiceModel/tools/scripts/BuildTest.cmd @@ -0,0 +1,8 @@ +:: Build tests on Docker host machine. + +:: Windows Release Build +call ..\..\..\..\eng\common\cibuild.cmd -configuration Release -prepareMachine /p:Root_Certificate_Installed=true /p:Client_Certificate_Installed=true /p:SSL_Available=true /p:Test=false + + + + diff --git a/src/System.Private.ServiceModel/tools/scripts/DockerStartWCFService.cmd b/src/System.Private.ServiceModel/tools/scripts/DockerStartWCFService.cmd new file mode 100644 index 00000000000..471072b29cf --- /dev/null +++ b/src/System.Private.ServiceModel/tools/scripts/DockerStartWCFService.cmd @@ -0,0 +1,68 @@ +echo off +setlocal +echo ********************************** +echo Starting WCF Service on Docker +echo ********************************** + +:: Use this script to start docker container for WCF Services - IIS Hosted and Self Hosted + +:: Variables +set _exitCode=0 +set "ServiceImageTag=wcf:service" +set "ServiceContainerName=WCFServiceContainer" +set "ServiceHostName=wcfservicehost" + +:: Check if docker is running +docker ps>nul 2>&1 +if ERRORLEVEL 1 ( + echo. & echo ERROR: Please make sure docker is running. + goto :Failure +) + +:: Check if docker is using Windows Containers +CALL "C:\Program Files\Docker\Docker\DockerCli.exe" -SwitchWindowsEngine + +:: Check if WCF service is already running +FOR /F "tokens=* USEBACKQ" %%F IN (`docker container inspect -f '{{.State.Status}}' %ServiceContainerName%`) DO ( +if %%F == 'running' ( + echo. & echo WCF Service container is already running. + goto :Done +)) + +:: Change directory to wcf folder +cd ../../../.. + +echo. & echo Building Docker image for WCF service + +:: Building docker image. +docker build -f ./Docker/Service/Dockerfile -t %ServiceImageTag% . +if ERRORLEVEL 1 ( + echo. & echo ERROR: Building docker image failed. + goto :Failure +) +echo. & echo Building image success.. + +:: Starting docker container from the image. +echo. & echo Starting WCF Service Container +:: Run docker container and mount current directory for wcf source as container volume - C:\wcf +docker run --name %ServiceContainerName% --rm -it -d -h %ServiceHostName% -v "%cd%":"C:\wcf" %ServiceImageTag% +if ERRORLEVEL 1 ( + echo. & echo ERROR: Starting WCF service container failed. + goto :Failure +) + +echo. & echo Started WCF Service Container. +:: Print service container IP address and host name +echo. & echo WCF Service Container IP address and Host name: +docker inspect --format="{{.NetworkSettings.Networks.nat.IPAddress}}" %ServiceContainerName% +echo %ServiceHostName% + +exit /b + +:Failure +echo. & echo Error... +set _exitCode=1 + +:Done +exit /b %_exitCode% +endlocal diff --git a/src/System.Private.ServiceModel/tools/scripts/DockerStartWCFTest-Linux.cmd b/src/System.Private.ServiceModel/tools/scripts/DockerStartWCFTest-Linux.cmd new file mode 100644 index 00000000000..19200d21a99 --- /dev/null +++ b/src/System.Private.ServiceModel/tools/scripts/DockerStartWCFTest-Linux.cmd @@ -0,0 +1,77 @@ +echo off +setlocal +echo ********************************** +echo Starting WCF Client on Docker +echo ********************************** + +:: Use this script to start docker Linux container for WCF Client + +:: Variables +set _exitCode=0 +set "TestContainerName=WCFTestContainerLinux" +set "ServiceContainerName=WCFServiceContainer" +set "ServiceHostName=wcfservicehost" + +:: Check if docker is running +docker ps>nul 2>&1 +if ERRORLEVEL 1 ( + echo. & echo ERROR: Please make sure docker is running. + goto :Failure +) + +echo. & echo Checking WCF service container status and IP address. + +:: Switch to Windows Containers to check WCF Service status +START /B /WAIT "" "C:\Program Files\Docker\Docker\DockerCli.exe" -SwitchWindowsEngine + +:: Check if WCF service is already running +docker container inspect -f '{{.State.Status}}' %ServiceContainerName% +if ERRORLEVEL 1 ( + echo. & echo Warning: WCF Service container is not running. + CALL DockerStartWCFService.cmd +) + +:: set ServiceUri +FOR /F "tokens=* USEBACKQ" %%F IN (`docker inspect --format="{{.NetworkSettings.Networks.nat.IPAddress}}" %ServiceContainerName%`) DO ( +:: SET ServiceIPAddress=%%F +SET ServiceUri=%ServiceHostName%/WcfService38 +) +echo %ServiceUri% + +:: Switch to Linux Containers to run Linux tests +START /B /WAIT "" "C:\Program Files\Docker\Docker\DockerCli.exe" -SwitchLinuxEngine + +:: Change directory to wcf src +cd ../../../.. + +echo. & echo Building Docker image for WCF client + +:: Building docker image. +docker build -f ./Docker/Client/Linux.dockerfile --tag=wcf:client . +if ERRORLEVEL 1 ( + echo. & echo ERROR: Building docker image failed. + goto :Failure +) +echo. & echo Building image success.. + +:: Starting docker container from the image. +echo. & echo Starting WCF client +:: run docker container and mount current directory for wcf source as container volume '/wcf' +:: mount volume '.dotnet-linux' CLI cache directory inside the container as '.dotnet' +:: mount volume 'artifacts-linux' inside the container as 'artifacts' +:: mount volumes 'artifacts/bin' and 'artifacts/obj' inside the container, since it contains the test assemblies +docker run --name %TestContainerName% --rm -it --memory=4g -v "%cd%":"/wcf" -v "%cd%/.dotnet-linux":"/wcf/.dotnet" -v "%cd%/artifacts-linux":"/wcf/artifacts" -v "%cd%/artifacts/bin":"/wcf/artifacts/bin" -v "%cd%/artifacts/obj":"/wcf/artifacts/obj" -e ServiceUri=%ServiceUri% wcf:client +if ERRORLEVEL 1 ( + echo. & echo ERROR: Starting WCF client container failed. + goto :Failure +) + +exit /b + +:Failure +echo. & echo Error... +set _exitCode=1 + +:Done +exit /b %_exitCode% +endlocal diff --git a/src/System.Private.ServiceModel/tools/scripts/DockerStartWCFTest-Windows.cmd b/src/System.Private.ServiceModel/tools/scripts/DockerStartWCFTest-Windows.cmd new file mode 100644 index 00000000000..470301145c6 --- /dev/null +++ b/src/System.Private.ServiceModel/tools/scripts/DockerStartWCFTest-Windows.cmd @@ -0,0 +1,72 @@ +echo off +setlocal +echo ********************************** +echo Starting WCF Client on Docker +echo ********************************** + +:: Use this script to start docker Windows container for WCF Client + +:: Variables +set _exitCode=0 +set "TestContainerName=WCFTestContainerWin" +set "ServiceContainerName=WCFServiceContainer" +set "ServiceHostName=wcfservicehost" + +:: Check if docker is running +docker ps>nul 2>&1 +if ERRORLEVEL 1 ( + echo. & echo ERROR: Please make sure docker is running. + goto :Failure +) + +echo. & echo Checking WCF service container status and IP address. + +:: Switch to Windows Containers to check WCF Service status +START /B /WAIT "" "C:\Program Files\Docker\Docker\DockerCli.exe" -SwitchWindowsEngine + +:: Check if WCF service is already running +docker container inspect -f '{{.State.Status}}' %ServiceContainerName% +if ERRORLEVEL 1 ( + echo. & echo Warning: WCF Service container is not running. + CALL DockerStartWCFService.cmd +) + +:: set ServiceUri +FOR /F "tokens=* USEBACKQ" %%F IN (`docker inspect --format="{{.NetworkSettings.Networks.nat.IPAddress}}" %ServiceContainerName%`) DO ( +:: SET ServiceIPAddress=%%F +SET ServiceUri=%ServiceHostName%/WcfService38 +) +echo %ServiceUri% + +:: Change directory to wcf src +cd ../../../.. + +echo. & echo Building Docker image for WCF client + +:: Building docker image. +docker build -f ./Docker/Client/Windows.dockerfile --tag=wcf:client . +if ERRORLEVEL 1 ( + echo. & echo ERROR: Building docker image failed. + goto :Failure +) +echo. & echo Building image success.. + +:: Starting docker container from the image. + +echo. & echo Starting WCF client +:: run docker container and mount current directory for wcf source as container volume C:\wcf +docker run --name %TestContainerName% --rm -it --memory=4g -v "%cd%":"C:\wcf" -e ServiceUri=%ServiceUri% wcf:client +if ERRORLEVEL 1 ( + echo. & echo ERROR: Starting WCF client container failed. + goto :Failure +) + +exit /b + +:Failure +echo. & echo Error... +set _exitCode=1 + +:Done +exit /b %_exitCode% +endlocal diff --git a/src/System.Private.ServiceModel/tools/scripts/InstallRootCertificate.sh b/src/System.Private.ServiceModel/tools/scripts/InstallRootCertificate.sh index fae4b6d8ff5..b4ecaade001 100755 --- a/src/System.Private.ServiceModel/tools/scripts/InstallRootCertificate.sh +++ b/src/System.Private.ServiceModel/tools/scripts/InstallRootCertificate.sh @@ -20,10 +20,16 @@ acquire_certificate() echo "Obtaining certificate from '$ServiceUri'" - # Need to make a call as the original user as we need to write to the cert store for the current - # user, not as root - echo "Making a call to '${__service_host}/TestHost.svc/RootCert' as user '$SUDO_USER'" - sudo -E -u $SUDO_USER $__curl_exe -o $__cafile "http://${__service_host}/TestHost.svc/RootCert?asPem=true" + # Need to make a call as the original user as we need to write to the cert store for the current user, not as root + # if $EUID = 0, user is 'root' + if [ "$EUID" -ne 0 ]; then + echo "Making a call to '${__service_host}/TestHost.svc/RootCert' as user '$SUDO_USER'" + sudo -E -u $SUDO_USER $__curl_exe -o $__cafile "http://${__service_host}/TestHost.svc/RootCert?asPem=true" + else + # Docker containers has no Sudo installed, by default it is running root user + echo "Making a call to '${ServiceUri}/TestHost.svc/RootCert' as root user" + $__curl_exe -o $__cafile "http://${ServiceUri}/TestHost.svc/RootCert?asPem=true" + fi return $? } diff --git a/src/System.Private.ServiceModel/tools/scripts/SetClientEnv-Linux.sh b/src/System.Private.ServiceModel/tools/scripts/SetClientEnv-Linux.sh new file mode 100644 index 00000000000..279cfaa92e0 --- /dev/null +++ b/src/System.Private.ServiceModel/tools/scripts/SetClientEnv-Linux.sh @@ -0,0 +1,15 @@ +# Setup environment variables +export Windows_Authentication_Available=true +export SPN_Available=true +export Server_Domain_Joined=true +export Ambient_Credentials_Available=true +export Domain_Available=true +export Explicit_Credentials_Available=true +# Set username and password +#export ExplicitUserName= +#export ExplicitPassword= +export SSL_Available=true +export Root_Certificate_Installed=true +export Client_Certificate_Installed=true +export Peer_Certificate_Installed=true +#export NegotiateTestDomain= diff --git a/src/System.Private.ServiceModel/tools/scripts/SetClientEnv-Windows.cmd b/src/System.Private.ServiceModel/tools/scripts/SetClientEnv-Windows.cmd new file mode 100644 index 00000000000..08534527e62 --- /dev/null +++ b/src/System.Private.ServiceModel/tools/scripts/SetClientEnv-Windows.cmd @@ -0,0 +1,15 @@ +:: Setup environment variables +setx Windows_Authentication_Available true +setx Digest_Authentication_Available true +setx Ambient_Credentials_Available true +setx SPN_Available true +setx NTLM_Available true +setx Server_Domain_Joined true +:: Set username and password +::setx ExplicitUserName +::setx ExplicitPassword +setx Domain_Available true +setx UPN_Available true +setx Root_Certificate_Installed true +setx Client_Certificate_Installed true +setx Peer_Certificate_Installed true diff --git a/src/System.Private.ServiceModel/tools/scripts/SetupWcfIISHostedService.cmd b/src/System.Private.ServiceModel/tools/scripts/SetupWcfIISHostedService.cmd index a677dd17217..941f5390e3a 100644 --- a/src/System.Private.ServiceModel/tools/scripts/SetupWcfIISHostedService.cmd +++ b/src/System.Private.ServiceModel/tools/scripts/SetupWcfIISHostedService.cmd @@ -55,7 +55,7 @@ goto :NextArg :: Make sure this script is running in elevated if EXIST %_logFile% del %_logFile% /f /q -net session>nul 2>&1 +openfiles >nul 2>&1 if ERRORLEVEL 1 ( echo. & echo ERROR: Please run this script with elevated permission. goto :Failure @@ -181,13 +181,17 @@ if EXIST %_masterRepo% ( ) echo Use %_certService% for certificate service -echo Build CertificateGenerator tool -call :Run %_certRepo%\src\System.Private.ServiceModel\tools\scripts\BuildCertUtil.cmd -if ERRORLEVEL 1 goto :Failure echo Run CertificateGenerator tool. This will take a little while... md %_wcfTestDir% set certGen=%_certRepo%\artifacts\bin\CertificateGenerator\Release\CertificateGenerator.exe + +IF NOT EXIST "%certGen%" ( + echo Build CertificateGenerator tool + call :Run %_certRepo%\src\System.Private.ServiceModel\tools\scripts\BuildCertUtil.cmd + if ERRORLEVEL 1 goto :Failure +) + echo ^^^^^^^^^^^>%certGen%.config call :Run %certGen% if ERRORLEVEL 1 goto :Failure diff --git a/src/System.Private.ServiceModel/tools/scripts/StartWCFSelfHostedSvcDoWork.cmd b/src/System.Private.ServiceModel/tools/scripts/StartWCFSelfHostedSvcDoWork.cmd index 5bdf5aa410e..5efd40c7048 100644 --- a/src/System.Private.ServiceModel/tools/scripts/StartWCFSelfHostedSvcDoWork.cmd +++ b/src/System.Private.ServiceModel/tools/scripts/StartWCFSelfHostedSvcDoWork.cmd @@ -13,22 +13,28 @@ echo Preparing to launch the WCF self hosted service if EXIST %_setupSemaphoreFile% del %_setupSemaphoreFile% +set wcfSelfhosted=%~dp0..\..\..\..\artifacts\bin\SelfHostedWcfService\Release\SelfHostedWcfService.exe REM Build tools -echo Building the WCF Self hosted service... -call %~dp0BuildWCFSelfHostedService.cmd >>%_setuplog% -SET __EXITCODE=%ERRORLEVEL% -if NOT [%__EXITCODE%]==[0] ( - echo ERROR: An error occurred while building WCF Self hosted Service. >>%_setuplog% - goto :done - ) - -echo Building the certificate generator ... -call %~dp0BuildCertUtil.cmd >>%_setuplog% -set __EXITCODE=%ERRORLEVEL% -if NOT [%__EXITCODE%]==[0] ( - echo ERROR: An error occurred while building the Certificate generator. >>%_setuplog% - goto :done - ) +IF NOT EXIST "%wcfSelfhosted%" ( + echo Building the WCF Self hosted service... + call %~dp0BuildWCFSelfHostedService.cmd >>%_setuplog% + SET __EXITCODE=%ERRORLEVEL% + if NOT [%__EXITCODE%]==[0] ( + echo ERROR: An error occurred while building WCF Self hosted Service. >>%_setuplog% + goto :done + ) +) + +set certGen=%~dp0..\..\..\..\artifacts\bin\CertificateGenerator\Release\CertificateGenerator.exe +IF NOT EXIST "%certGen%" ( + echo Building the certificate generator ... + call %~dp0BuildCertUtil.cmd >>%_setuplog% + set __EXITCODE=%ERRORLEVEL% + if NOT [%__EXITCODE%]==[0] ( + echo ERROR: An error occurred while building the Certificate generator. >>%_setuplog% + goto :done + ) +) REM Config Certs REM we need the direcotry to save the test.crl file. We are investigate a way to get rid of it