From cf1c9950a097e83abd372174b521224d1f7598f0 Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Sat, 31 Mar 2018 07:32:14 +0200 Subject: [PATCH] Run integration tests as part of CI (after #129) (#131) * Run CI scripts on both Mac and Linux * Fix AuthTests for macOS * Use SocketsHttpHandler * Install minikube on the Travis CI servers * Add integration tests * Fix an issue where StreamConnectAsync would crash if the credentials were not set --- .travis.yml | 41 ++++++++++++++++++++++++++--------------- examples/nginx.yml | 10 ++++++++++ install-linux.sh | 27 +++++++++++++++++++++++++++ install-osx.sh | 8 ++++++++ integration-tests.sh | 21 +++++++++++++++++++++ tests/AuthTests.cs | 38 ++++++++++++++++++++++++++++++++++---- 6 files changed, 126 insertions(+), 19 deletions(-) create mode 100644 examples/nginx.yml create mode 100755 install-linux.sh create mode 100755 install-osx.sh create mode 100755 integration-tests.sh diff --git a/.travis.yml b/.travis.yml index 06106f0..330500a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,30 @@ +sudo: required +dist: trusty + +os: + - osx + - linux + language: csharp -sudo: false -matrix: - include: - - mono: none - dist: trusty - # We need the .NET Core 2.1 (preview 1) SDK to build. Travis doesn't know how to install this yet. - before_install: - - echo 'Installing .NET Core...' - - export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 - - export DOTNET_CLI_TELEMETRY_OPTOUT=1 - - curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg - - sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg - - sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-trusty-prod trusty main" > /etc/apt/sources.list.d/dotnetdev.list' - - sudo apt-get -qq update - - sudo apt-get install -y dotnet-sdk-2.1.300-preview1-008174 +mono: none +env: + global: + - DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 + - DOTNET_CLI_TELEMETRY_OPTOUT=1 + - COMPlus_UseManagedHttpClientHandler=true + +# minikube-related changes + - CHANGE_MINIKUBE_NONE_USER=true + - MINIKUBE_WANTREPORTERRORPROMPT=false + - MINIKUBE_WANTUPDATENOTIFICATION=false + - KUBECONFIG=/home/travis/.kube/config + +# We need the .NET Core 2.1 (preview 1) SDK to build. Travis doesn't know how to install this yet. +before_install: + - ./install-$TRAVIS_OS_NAME.sh script: - ./ci.sh + +after_script: + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then ./integration-tests.sh; fi \ No newline at end of file diff --git a/examples/nginx.yml b/examples/nginx.yml new file mode 100644 index 0000000..b92a713 --- /dev/null +++ b/examples/nginx.yml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - containerPort: 80 \ No newline at end of file diff --git a/install-linux.sh b/install-linux.sh new file mode 100755 index 0000000..2d28e45 --- /dev/null +++ b/install-linux.sh @@ -0,0 +1,27 @@ +#!/bin/sh +echo 'Installing .NET Core...' + +curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg +sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg +sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-trusty-prod trusty main" > /etc/apt/sources.list.d/dotnetdev.list' +sudo apt-get -qq update +sudo apt-get install -y dotnet-sdk-2.1.300-preview1-008174 + +echo 'Installing kubecl' +curl -Lo kubectl https://storage.googleapis.com/kubernetes-release/release/v1.9.0/bin/linux/amd64/kubectl +chmod +x kubectl +sudo mv kubectl /usr/local/bin/ + +echo 'Installing minikube' +curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.25.0/minikube-linux-amd64 +chmod +x minikube +sudo mv minikube /usr/local/bin/ + +echo 'Creating the minikube cluster' +sudo minikube start --vm-driver=none --kubernetes-version=v1.9.0 --extra-config=apiserver.Authorization.Mode=RBAC +minikube update-context +minikube addons disable dashboard + +echo 'Waiting for the cluster nodes to be ready' +JSONPATH='{range .items[*]}{@.metadata.name}:{range @.status.conditions[*]}{@.type}={@.status};{end}{end}'; \ + until kubectl get nodes -o jsonpath="$JSONPATH" 2>&1 | grep -q "Ready=True"; do sleep 1; done diff --git a/install-osx.sh b/install-osx.sh new file mode 100755 index 0000000..d0be1b2 --- /dev/null +++ b/install-osx.sh @@ -0,0 +1,8 @@ +#!/bin/sh +echo 'Installing .NET Core...' + +wget https://download.microsoft.com/download/D/7/8/D788D3CD-44C4-487D-829B-413E914FB1C3/dotnet-sdk-2.1.300-preview1-008174-osx-x64.pkg -O ~/dotnet-sdk-2.1.300-preview1-008174-osx-x64.pkg +sudo installer -pkg ~/dotnet-sdk-2.1.300-preview1-008174-osx-x64.pkg -target / + +# https://github.com/dotnet/cli/issues/2544 +ln -s /usr/local/share/dotnet/dotnet /usr/local/bin/ diff --git a/integration-tests.sh b/integration-tests.sh new file mode 100755 index 0000000..162565a --- /dev/null +++ b/integration-tests.sh @@ -0,0 +1,21 @@ +#!/bin/sh +cd examples + +echo 'Creating a nginx pod in the default namespace' +kubectl create -f nginx.yml + +echo 'Running the simple example' +cd simple +dotnet run + +echo 'Running the exec example' +cd ../exec +dotnet run + +echo 'Running the labels example' +cd ../labels +dotnet run + +echo 'Running the namespace example' +cd ../namespace +dotnet run \ No newline at end of file diff --git a/tests/AuthTests.cs b/tests/AuthTests.cs index cc1a0c9..18b4317 100644 --- a/tests/AuthTests.cs +++ b/tests/AuthTests.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Net; using System.Net.Http.Headers; +using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading.Tasks; @@ -11,6 +12,9 @@ using k8s.Tests.Mock; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Server.Kestrel.Https; using Microsoft.Rest; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Pkcs; +using Org.BouncyCastle.Security; using Xunit; using Xunit.Abstractions; @@ -46,7 +50,7 @@ namespace k8s.Tests using (var server = new MockKubeApiServer(TestOutput, cxt => { - cxt.Response.StatusCode = (int) HttpStatusCode.Unauthorized; + cxt.Response.StatusCode = (int)HttpStatusCode.Unauthorized; return Task.FromResult(false); })) { @@ -76,7 +80,7 @@ namespace k8s.Tests if (header != expect) { - cxt.Response.StatusCode = (int) HttpStatusCode.Unauthorized; + cxt.Response.StatusCode = (int)HttpStatusCode.Unauthorized; return Task.FromResult(false); } @@ -167,8 +171,13 @@ namespace k8s.Tests var clientCertificateKeyData = File.ReadAllText("assets/client-key-data.txt"); var clientCertificateData = File.ReadAllText("assets/client-certificate-data.txt"); + + X509Certificate2 serverCertificate = null; + using (MemoryStream serverCertificateStream = new MemoryStream(Convert.FromBase64String(serverCertificateData))) + { + serverCertificate = OpenCertificateStore(serverCertificateStream); + } - var serverCertificate = new X509Certificate2(Convert.FromBase64String(serverCertificateData), ""); var clientCertificate = new X509Certificate2(Convert.FromBase64String(clientCertificateData), ""); var clientCertificateValidationCalled = false; @@ -263,7 +272,7 @@ namespace k8s.Tests if (header != expect) { - cxt.Response.StatusCode = (int) HttpStatusCode.Unauthorized; + cxt.Response.StatusCode = (int)HttpStatusCode.Unauthorized; return Task.FromResult(false); } @@ -319,6 +328,27 @@ namespace k8s.Tests Assert.Equal(HttpStatusCode.Unauthorized, listTask.Response.StatusCode); } } + } + + private X509Certificate2 OpenCertificateStore(Stream stream) + { + Pkcs12Store store = new Pkcs12Store(); + store.Load(stream, new char[] { }); + + var keyAlias = store.Aliases.Cast().SingleOrDefault(a => store.IsKeyEntry(a)); + + var key = (RsaPrivateCrtKeyParameters)store.GetKey(keyAlias).Key; + var bouncyCertificate = store.GetCertificate(keyAlias).Certificate; + + var certificate = new X509Certificate2(DotNetUtilities.ToX509Certificate(bouncyCertificate)); + var parameters = DotNetUtilities.ToRSAParameters(key); + + RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); + rsa.ImportParameters(parameters); + + certificate = RSACertificateExtensions.CopyWithPrivateKey(certificate, rsa); + + return certificate; } } }