From ce76824dd50f485e132aeee86773ca03e92de7d8 Mon Sep 17 00:00:00 2001 From: Tara Gu Date: Wed, 14 Aug 2019 16:26:59 -0400 Subject: [PATCH 1/3] Add https and gateway setup logic and make helloworld test able to run with https flag on --- .../config/testdata/config-defaults.yaml | 1 + test/README.md | 5 + .../api/v1alpha1/blue_green_test.go | 3 +- .../api/v1alpha1/generatename_test.go | 4 +- .../api/v1alpha1/resources_test.go | 4 +- test/conformance/api/v1alpha1/service_test.go | 13 +- .../api/v1alpha1/single_threaded_test.go | 4 +- test/conformance/api/v1alpha1/volumes_test.go | 20 +- .../runtime/readiness_probe_test.go | 4 +- test/conformance/runtime/util.go | 4 +- test/e2e-common.sh | 14 + test/e2e-tests.sh | 4 +- test/e2e-upgrade-tests.sh | 8 +- test/e2e/activator_test.go | 4 +- test/e2e/autoscale_test.go | 3 +- test/e2e/destroypod_test.go | 8 +- test/e2e/egress_traffic_test.go | 4 +- test/e2e/grpc_test.go | 4 +- test/e2e/helloworld_test.go | 27 +- test/e2e/istio/probing_test.go | 5 +- test/e2e/namespace_test.go | 9 +- test/e2e/rollback_byo_test.go | 4 +- test/e2e/service_to_service_test.go | 12 +- test/e2e/subroutes_test.go | 12 +- test/e2e/websocket_test.go | 6 +- test/e2e_flags.go | 3 + test/performance/latency_test.go | 3 +- test/performance/observed_concurency_test.go | 3 +- test/performance/scale_from_zero_test.go | 6 +- test/v1alpha1/service.go | 261 +++++++++++++++++- 30 files changed, 406 insertions(+), 56 deletions(-) create mode 120000 pkg/reconciler/revision/config/testdata/config-defaults.yaml diff --git a/pkg/reconciler/revision/config/testdata/config-defaults.yaml b/pkg/reconciler/revision/config/testdata/config-defaults.yaml new file mode 120000 index 000000000000..93ce67f647a6 --- /dev/null +++ b/pkg/reconciler/revision/config/testdata/config-defaults.yaml @@ -0,0 +1 @@ +../../../../../config/config-defaults.yaml \ No newline at end of file diff --git a/test/README.md b/test/README.md index 226fafdbb45a..1a5f73ee0d22 100644 --- a/test/README.md +++ b/test/README.md @@ -169,6 +169,7 @@ these flags: - [`--tag`](#using-a-docker-tag) - [`--ingressendpoint`](#using-a-custom-ingress-endpoint) - [`--resolvabledomain`](#using-a-resolvable-domain) +- [`--https`](#using-https) ### Overridding docker repo @@ -226,3 +227,7 @@ the header. If you have configured your cluster to use a resolvable domain, you can use the `--resolvabledomain` flag to indicate that the test should make requests directly against `Route.Status.Domain` and does not need to spoof the `Host`. + +### Using https + +You can use the `--https` flag to have all tests run with https. diff --git a/test/conformance/api/v1alpha1/blue_green_test.go b/test/conformance/api/v1alpha1/blue_green_test.go index 64f1ea4d0691..90a02c24473f 100644 --- a/test/conformance/api/v1alpha1/blue_green_test.go +++ b/test/conformance/api/v1alpha1/blue_green_test.go @@ -68,7 +68,8 @@ func TestBlueGreenRoute(t *testing.T) { // Setup Initial Service t.Log("Creating a new Service in runLatest") - objects, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names) + objects, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */) if err != nil { t.Fatalf("Failed to create initial Service: %v: %v", names.Service, err) } diff --git a/test/conformance/api/v1alpha1/generatename_test.go b/test/conformance/api/v1alpha1/generatename_test.go index c42621683229..66d8aed0d021 100644 --- a/test/conformance/api/v1alpha1/generatename_test.go +++ b/test/conformance/api/v1alpha1/generatename_test.go @@ -124,7 +124,9 @@ func TestServiceGenerateName(t *testing.T) { // Create the service using the generate name field. If the service does not become ready this will fail. t.Logf("Creating new service with generateName %s", generateName) - resources, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, setServiceGenerateName(generateName)) + resources, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + setServiceGenerateName(generateName)) if err != nil { t.Fatalf("Failed to create service with generateName %s: %v", generateName, err) } diff --git a/test/conformance/api/v1alpha1/resources_test.go b/test/conformance/api/v1alpha1/resources_test.go index d3e0c1711c3c..9700cc7fe5b3 100644 --- a/test/conformance/api/v1alpha1/resources_test.go +++ b/test/conformance/api/v1alpha1/resources_test.go @@ -55,7 +55,9 @@ func TestCustomResourcesLimits(t *testing.T) { test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) defer test.TearDown(clients, names) - objects, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, v1a1opts.WithResourceRequirements(resources)) + objects, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + v1a1opts.WithResourceRequirements(resources)) if err != nil { t.Fatalf("Failed to create initial Service %v: %v", names.Service, err) } diff --git a/test/conformance/api/v1alpha1/service_test.go b/test/conformance/api/v1alpha1/service_test.go index 5aceffde0e96..dd01a63c4866 100644 --- a/test/conformance/api/v1alpha1/service_test.go +++ b/test/conformance/api/v1alpha1/service_test.go @@ -53,7 +53,8 @@ func TestRunLatestService(t *testing.T) { test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) // Setup initial Service - objects, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names) + objects, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */) if err != nil { t.Fatalf("Failed to create initial Service %v: %v", names.Service, err) } @@ -196,7 +197,9 @@ func TestRunLatestServiceBYOName(t *testing.T) { revName := names.Service + "-byoname" // Setup initial Service - objects, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, func(svc *v1alpha1.Service) { + objects, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + func(svc *v1alpha1.Service) { svc.Spec.ConfigurationSpec.GetTemplate().Name = revName }) if err != nil { @@ -265,7 +268,8 @@ func TestReleaseService(t *testing.T) { ) // Setup initial Service - objects, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names) + objects, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */) if err != nil { t.Fatalf("Failed to create initial Service %v: %v", names.Service, err) } @@ -529,7 +533,8 @@ func TestAnnotationPropagation(t *testing.T) { test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) // Setup initial Service - objects, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names) + objects, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */) if err != nil { t.Fatalf("Failed to create initial Service %v: %v", names.Service, err) } diff --git a/test/conformance/api/v1alpha1/single_threaded_test.go b/test/conformance/api/v1alpha1/single_threaded_test.go index 3e333c525328..f76f493fa0fb 100644 --- a/test/conformance/api/v1alpha1/single_threaded_test.go +++ b/test/conformance/api/v1alpha1/single_threaded_test.go @@ -45,7 +45,9 @@ func TestSingleConcurrency(t *testing.T) { test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) defer test.TearDown(clients, names) - objects, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, v1a1opts.WithContainerConcurrency(1)) + objects, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + v1a1opts.WithContainerConcurrency(1)) if err != nil { t.Fatalf("Failed to create Service: %v", err) } diff --git a/test/conformance/api/v1alpha1/volumes_test.go b/test/conformance/api/v1alpha1/volumes_test.go index 9a733909c22c..bf93aed41f2a 100644 --- a/test/conformance/api/v1alpha1/volumes_test.go +++ b/test/conformance/api/v1alpha1/volumes_test.go @@ -90,7 +90,9 @@ func TestConfigMapVolume(t *testing.T) { }) // Setup initial Service - if _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, withVolume, withOptionalBadVolume); err != nil { + if _, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + withVolume, withOptionalBadVolume); err != nil { t.Fatalf("Failed to create initial Service %v: %v", names.Service, err) } @@ -162,7 +164,9 @@ func TestProjectedConfigMapVolume(t *testing.T) { }) // Setup initial Service - if _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, withVolume); err != nil { + if _, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + withVolume); err != nil { t.Fatalf("Failed to create initial Service %v: %v", names.Service, err) } @@ -228,7 +232,9 @@ func TestSecretVolume(t *testing.T) { }) // Setup initial Service - if _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, withVolume, withOptionalBadVolume); err != nil { + if _, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + withVolume, withOptionalBadVolume); err != nil { t.Fatalf("Failed to create initial Service %v: %v", names.Service, err) } @@ -298,7 +304,9 @@ func TestProjectedSecretVolume(t *testing.T) { } // Setup initial Service - if _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, withVolume, withSubpath); err != nil { + if _, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + withVolume, withSubpath); err != nil { t.Fatalf("Failed to create initial Service %v: %v", names.Service, err) } @@ -395,7 +403,9 @@ func TestProjectedComplex(t *testing.T) { }) // Setup initial Service - if _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, withVolume); err != nil { + if _, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + withVolume); err != nil { t.Fatalf("Failed to create initial Service %v: %v", names.Service, err) } diff --git a/test/conformance/runtime/readiness_probe_test.go b/test/conformance/runtime/readiness_probe_test.go index 10499dc6a04e..dede27106a68 100644 --- a/test/conformance/runtime/readiness_probe_test.go +++ b/test/conformance/runtime/readiness_probe_test.go @@ -44,7 +44,9 @@ func TestProbeRuntime(t *testing.T) { defer test.TearDown(clients, names) t.Log("Creating a new Service") - _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, v1a1opts.WithReadinessProbe( + _, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + v1a1opts.WithReadinessProbe( &corev1.Probe{ Handler: corev1.Handler{ HTTPGet: &corev1.HTTPGetAction{ diff --git a/test/conformance/runtime/util.go b/test/conformance/runtime/util.go index c11c803493f0..7df4ec093656 100644 --- a/test/conformance/runtime/util.go +++ b/test/conformance/runtime/util.go @@ -54,7 +54,9 @@ func fetchRuntimeInfo( svc.Spec.Template.Spec.Containers[0].ImagePullPolicy = "Always" }) - objects, err := v1a1test.CreateRunLatestServiceReady(t, clients, names, serviceOpts...) + objects, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + serviceOpts...) if err != nil { return nil, nil, err } diff --git a/test/e2e-common.sh b/test/e2e-common.sh index 5edbc5eeeba7..f267a652c943 100644 --- a/test/e2e-common.sh +++ b/test/e2e-common.sh @@ -29,6 +29,8 @@ CERT_MANAGER_VERSION="0.9.1" ISTIO_VERSION="" GLOO_VERSION="" +HTTPS=0 + # Current YAMLs used to install Knative Serving. INSTALL_RELEASE_YAML="" INSTALL_MONITORING_YAML="" @@ -68,6 +70,10 @@ function parse_flags() { readonly MESH=0 return 1 ;; + --https) + readonly HTTPS=1 + return 1 + ;; --install-monitoring) readonly INSTALL_MONITORING=1 return 1 @@ -290,6 +296,14 @@ function use_resolvable_domain() { echo "false" } +# Check if we should use --https. +function use_https() { + if (( HTTPS )); then + echo "--https" + else + echo "" + fi +} # Uninstalls Knative Serving from the current cluster. function knative_teardown() { diff --git a/test/e2e-tests.sh b/test/e2e-tests.sh index 8ae8e2221a7a..89ab63556390 100755 --- a/test/e2e-tests.sh +++ b/test/e2e-tests.sh @@ -52,7 +52,7 @@ go_test_e2e -timeout=30m \ ./test/conformance/... \ ./test/e2e \ ${parallelism} \ - "--resolvabledomain=$(use_resolvable_domain)" || failed=1 + "--resolvabledomain=$(use_resolvable_domain)" "$(use_https)" || failed=1 # Run scale tests. go_test_e2e -timeout=10m \ @@ -63,7 +63,7 @@ go_test_e2e -timeout=10m \ if [[ -n "${ISTIO_VERSION}" ]]; then go_test_e2e -timeout=10m \ ./test/e2e/istio \ - "--resolvabledomain=$(use_resolvable_domain)" || failed=1 + "--resolvabledomain=$(use_resolvable_domain)" "$(use_https)" || failed=1 fi # Dump cluster state in case of failure diff --git a/test/e2e-upgrade-tests.sh b/test/e2e-upgrade-tests.sh index 6175e3a16d9b..e12304a3df71 100755 --- a/test/e2e-upgrade-tests.sh +++ b/test/e2e-upgrade-tests.sh @@ -68,7 +68,7 @@ TIMEOUT=10m header "Running preupgrade tests" go_test_e2e -tags=preupgrade -timeout=${TIMEOUT} ./test/upgrade \ - --resolvabledomain=$(use_resolvable_domain) || fail_test + --resolvabledomain=$(use_resolvable_domain) "$(use_https)" || fail_test header "Starting prober test" @@ -76,7 +76,7 @@ header "Starting prober test" rm -f /tmp/prober-signal go_test_e2e -tags=probe -timeout=${TIMEOUT} ./test/upgrade \ - --resolvabledomain=$(use_resolvable_domain) & + --resolvabledomain=$(use_resolvable_domain) "$(use_https)" & PROBER_PID=$! echo "Prober PID is ${PROBER_PID}" @@ -84,13 +84,13 @@ install_head header "Running postupgrade tests" go_test_e2e -tags=postupgrade -timeout=${TIMEOUT} ./test/upgrade \ - --resolvabledomain=$(use_resolvable_domain) || fail_test + --resolvabledomain=$(use_resolvable_domain) "$(use_https)" || fail_test install_latest_release header "Running postdowngrade tests" go_test_e2e -tags=postdowngrade -timeout=${TIMEOUT} ./test/upgrade \ - --resolvabledomain=$(use_resolvable_domain) || fail_test + --resolvabledomain=$(use_resolvable_domain) "$(use_https)" || fail_test # The prober is blocking on /tmp/prober-signal to know when it should exit. # diff --git a/test/e2e/activator_test.go b/test/e2e/activator_test.go index 1d350265c0e4..4dd4b1b13743 100644 --- a/test/e2e/activator_test.go +++ b/test/e2e/activator_test.go @@ -59,7 +59,9 @@ func TestActivatorOverload(t *testing.T) { t.Log("Creating a service with run latest configuration.") // Create a service with concurrency 1 that sleeps for N ms. // Limit its maxScale to 10 containers, wait for the service to scale down and hit it with concurrent requests. - resources, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, func(service *v1alpha1.Service) { + resources, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + func(service *v1alpha1.Service) { service.Spec.ConfigurationSpec.Template.Spec.ContainerConcurrency = ptr.Int64(1) service.Spec.ConfigurationSpec.Template.Annotations = map[string]string{"autoscaling.knative.dev/maxScale": "10"} }) diff --git a/test/e2e/autoscale_test.go b/test/e2e/autoscale_test.go index afae97e2b6f9..740aad4a6f1e 100644 --- a/test/e2e/autoscale_test.go +++ b/test/e2e/autoscale_test.go @@ -177,7 +177,8 @@ func setup(t *testing.T, class, metric string, target float64, targetUtilization Image: "autoscale", } test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) - resources, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + resources, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, append(fopts, rtesting.WithConfigAnnotations(map[string]string{ autoscaling.ClassAnnotationKey: class, autoscaling.MetricAnnotationKey: metric, diff --git a/test/e2e/destroypod_test.go b/test/e2e/destroypod_test.go index 12e37868b626..7d94be5f6da3 100644 --- a/test/e2e/destroypod_test.go +++ b/test/e2e/destroypod_test.go @@ -172,7 +172,9 @@ func TestDestroyPodTimely(t *testing.T) { defer test.TearDown(clients, names) test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) - objects, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, v1a1opts.WithRevisionTimeoutSeconds(int64(revisionTimeout.Seconds()))) + objects, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + v1a1opts.WithRevisionTimeoutSeconds(int64(revisionTimeout.Seconds()))) if err != nil { t.Fatalf("Failed to create a service: %v", err) } @@ -229,7 +231,9 @@ func TestDestroyPodWithRequests(t *testing.T) { defer test.TearDown(clients, names) test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) - objects, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, v1a1opts.WithRevisionTimeoutSeconds(int64(revisionTimeout.Seconds()))) + objects, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + v1a1opts.WithRevisionTimeoutSeconds(int64(revisionTimeout.Seconds()))) if err != nil { t.Fatalf("Failed to create a service: %v", err) } diff --git a/test/e2e/egress_traffic_test.go b/test/e2e/egress_traffic_test.go index c1c3b7d42fd6..33467436b0f2 100644 --- a/test/e2e/egress_traffic_test.go +++ b/test/e2e/egress_traffic_test.go @@ -49,7 +49,9 @@ func TestEgressTraffic(t *testing.T) { defer test.TearDown(clients, names) test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) - service, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, v1a1opts.WithEnv(envVars...)) + service, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + v1a1opts.WithEnv(envVars...)) if err != nil { t.Fatalf("Failed to create a service: %v", err) } diff --git a/test/e2e/grpc_test.go b/test/e2e/grpc_test.go index a358b354cf3b..a86b84f84921 100644 --- a/test/e2e/grpc_test.go +++ b/test/e2e/grpc_test.go @@ -169,7 +169,9 @@ func testGRPC(t *testing.T, f grpcTest, fopts ...rtesting.ServiceOption) { test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) defer test.TearDown(clients, names) - resources, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, fopts...) + resources, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + fopts...) if err != nil { t.Fatalf("Failed to create initial Service: %v: %v", names.Service, err) } diff --git a/test/e2e/helloworld_test.go b/test/e2e/helloworld_test.go index 0511d71985b3..dcac2b312012 100644 --- a/test/e2e/helloworld_test.go +++ b/test/e2e/helloworld_test.go @@ -46,23 +46,41 @@ func TestHelloWorld(t *testing.T) { Image: "helloworld", } + if test.ServingFlags.Https { + // Save the current Gateway to restore it after the test + oldGateway, err := clients.SharedClient.NetworkingV1alpha3().Gateways(v1a1test.Namespace).Get(v1a1test.GatewayName, metav1.GetOptions{}) + if err != nil { + t.Fatalf("Failed to get Gateway %s/%s", v1a1test.Namespace, v1a1test.GatewayName) + } + test.CleanupOnInterrupt(func () { v1a1test.RestoreGateway(t, clients, *oldGateway) }) + defer v1a1test.RestoreGateway(t, clients, *oldGateway) + } test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) defer test.TearDown(clients, names) t.Log("Creating a new Service") - resources, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names) + resources, httpsTransportOption, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, test.ServingFlags.Https) if err != nil { t.Fatalf("Failed to create initial Service: %v: %v", names.Service, err) } url := resources.Route.Status.URL.URL() - if _, err = pkgTest.WaitForEndpointState( + var opt interface{} + if test.ServingFlags.Https { + url.Scheme = "https" + if httpsTransportOption == nil { + t.Fatalf("Https transport option is nil") + } + opt = *httpsTransportOption + } + if _, err := pkgTest.WaitForEndpointState( clients.KubeClient, t.Logf, url, v1a1test.RetryingRouteInconsistency(pkgTest.MatchesAllOf(pkgTest.IsStatusOK, pkgTest.MatchesBody(test.HelloWorldText))), "HelloWorldServesText", - test.ServingFlags.ResolvableDomain); err != nil { + test.ServingFlags.ResolvableDomain, + opt); err != nil { t.Fatalf("The endpoint %s for Route %s didn't serve the expected text %q: %v", url, names.Route, test.HelloWorldText, err) } @@ -99,7 +117,8 @@ func TestQueueSideCarResourceLimit(t *testing.T) { defer test.TearDown(clients, names) t.Log("Creating a new Service") - resources, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + resources, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, v1a1opts.WithResourceRequirements(corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceName("cpu"): resource.MustParse("50m"), diff --git a/test/e2e/istio/probing_test.go b/test/e2e/istio/probing_test.go index 7313988d5f8a..34da838bc6ad 100644 --- a/test/e2e/istio/probing_test.go +++ b/test/e2e/istio/probing_test.go @@ -89,7 +89,8 @@ func TestIstioProbing(t *testing.T) { } test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) defer test.TearDown(clients, names) - objects, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names) + objects, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */) if err != nil { t.Fatalf("Failed to create Service %s: %v", names.Service, err) } @@ -264,7 +265,7 @@ func TestIstioProbing(t *testing.T) { // Create the service and wait for it to be ready test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) defer test.TearDown(clients, names) - _, err = v1a1test.CreateRunLatestServiceReady(t, clients, &names) + _, _, err = v1a1test.CreateRunLatestServiceReady(t, clients, &names, false /* https */) if err != nil { t.Fatalf("Failed to create Service %s: %v", names.Service, err) } diff --git a/test/e2e/namespace_test.go b/test/e2e/namespace_test.go index e945fd1b290a..0ef17b59b4cc 100644 --- a/test/e2e/namespace_test.go +++ b/test/e2e/namespace_test.go @@ -62,7 +62,8 @@ func TestMultipleNamespace(t *testing.T) { } test.CleanupOnInterrupt(func() { test.TearDown(defaultClients, defaultResources) }) defer test.TearDown(defaultClients, defaultResources) - if _, err := v1a1test.CreateRunLatestServiceReady(t, defaultClients, &defaultResources); err != nil { + if _, _, err := v1a1test.CreateRunLatestServiceReady(t, defaultClients, &defaultResources, + false /* https TODO(taragu) turn this on after helloworld test running with https */); err != nil { t.Fatalf("Failed to create Service %v in namespace %v: %v", defaultResources.Service, test.ServingNamespace, err) } @@ -72,7 +73,8 @@ func TestMultipleNamespace(t *testing.T) { } test.CleanupOnInterrupt(func() { test.TearDown(altClients, altResources) }) defer test.TearDown(altClients, altResources) - if _, err := v1a1test.CreateRunLatestServiceReady(t, altClients, &altResources); err != nil { + if _, _, err := v1a1test.CreateRunLatestServiceReady(t, altClients, &altResources, + false /* https TODO(taragu) turn this on after helloworld test running with https */); err != nil { t.Fatalf("Failed to create Service %v in namespace %v: %v", altResources.Service, test.AlternativeServingNamespace, err) } @@ -124,7 +126,8 @@ func TestConflictingRouteService(t *testing.T) { test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) defer test.TearDown(clients, names) - if _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names); err != nil { + if _, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */); err != nil { t.Errorf("Failed to create Service %v in namespace %v: %v", names.Service, test.ServingNamespace, err) } } diff --git a/test/e2e/rollback_byo_test.go b/test/e2e/rollback_byo_test.go index b23286e6a81c..2e5348edd19a 100644 --- a/test/e2e/rollback_byo_test.go +++ b/test/e2e/rollback_byo_test.go @@ -66,7 +66,9 @@ func TestRollbackBYOName(t *testing.T) { }) t.Logf("Creating a new Service with byo config name %q.", byoNameOld) - resources, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, withTrafficSpecOld, func(svc *v1alpha1.Service) { + resources, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + withTrafficSpecOld, func(svc *v1alpha1.Service) { svc.Spec.ConfigurationSpec.Template.ObjectMeta.Name = byoNameOld }) if err != nil { diff --git a/test/e2e/service_to_service_test.go b/test/e2e/service_to_service_test.go index 601791d02a6b..0b7f300ce15b 100644 --- a/test/e2e/service_to_service_test.go +++ b/test/e2e/service_to_service_test.go @@ -119,7 +119,8 @@ func testProxyToHelloworld(t *testing.T, clients *test.Clients, helloworldURL *u test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) defer test.TearDown(clients, names) - resources, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + resources, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, v1alph1testing.WithEnv(envVars...), v1alph1testing.WithConfigAnnotations(map[string]string{ autoscaling.WindowAnnotationKey: "6s", // shortest permitted; this is not required here, but for uniformity. @@ -195,7 +196,8 @@ func TestServiceToServiceCall(t *testing.T) { withInternalVisibility := v1alph1testing.WithServiceLabel( routeconfig.VisibilityLabelKey, routeconfig.VisibilityClusterLocal) - resources, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + resources, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, withInternalVisibility, v1alph1testing.WithConfigAnnotations(map[string]string{ autoscaling.WindowAnnotationKey: "6s", // shortest permitted; this is not required here, but for uniformity. @@ -241,7 +243,8 @@ func testSvcToSvcCallViaActivator(t *testing.T, clients *test.Clients, injectA b test.CleanupOnInterrupt(func() { test.TearDown(clients, testNames) }) defer test.TearDown(clients, testNames) - resources, err := v1a1test.CreateRunLatestServiceReady(t, clients, &testNames, + resources, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &testNames, + false /* https TODO(taragu) turn this on after helloworld test running with https */, v1alph1testing.WithConfigAnnotations(map[string]string{ autoscaling.TargetBurstCapacityKey: "-1", "sidecar.istio.io/inject": strconv.FormatBool(injectB), @@ -296,7 +299,8 @@ func TestCallToPublicService(t *testing.T) { test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) defer test.TearDown(clients, names) - resources, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + resources, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, v1alph1testing.WithConfigAnnotations(map[string]string{ autoscaling.WindowAnnotationKey: "6s", // shortest permitted; this is not required here, but for uniformity. })) diff --git a/test/e2e/subroutes_test.go b/test/e2e/subroutes_test.go index 9f900dba3c2f..6cc9ab602753 100644 --- a/test/e2e/subroutes_test.go +++ b/test/e2e/subroutes_test.go @@ -76,7 +76,9 @@ func TestSubrouteLocalSTS(t *testing.T) { // We can't use a longer more descript }, }) - resources, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, withInternalVisibility, withTrafficSpec) + resources, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + withInternalVisibility, withTrafficSpec) if err != nil { t.Fatalf("Failed to create initial Service: %v: %v", names.Service, err) } @@ -121,7 +123,9 @@ func TestSubrouteVisibilityPublicToPrivate(t *testing.T) { }, }}, }) - resources, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, withTrafficSpec) + resources, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + withTrafficSpec) if err != nil { t.Fatalf("Failed to create initial Service: %v: %w", names.Service, err) } @@ -250,7 +254,9 @@ func TestSubrouteVisibilityPrivateToPublic(t *testing.T) { }, }, }) - resources, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, withTrafficSpec, withInternalVisibility) + resources, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, + withTrafficSpec, withInternalVisibility) if err != nil { t.Fatalf("Failed to create initial Service: %v: %v", names.Service, err) } diff --git a/test/e2e/websocket_test.go b/test/e2e/websocket_test.go index d5a32f29ffdb..8815d572c355 100644 --- a/test/e2e/websocket_test.go +++ b/test/e2e/websocket_test.go @@ -124,7 +124,8 @@ func TestWebSocket(t *testing.T) { defer test.TearDown(clients, names) test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) - if _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names); err != nil { + if _, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */); err != nil { t.Fatalf("Failed to create WebSocket server: %v", err) } @@ -152,7 +153,8 @@ func TestWebSocketViaActivator(t *testing.T) { defer test.TearDown(clients, names) test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) - resources, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + resources, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, rtesting.WithConfigAnnotations(map[string]string{ autoscaling.TargetBurstCapacityKey: "-1", }), diff --git a/test/e2e_flags.go b/test/e2e_flags.go index bf55ab3fcb8a..e9fc5cd56684 100644 --- a/test/e2e_flags.go +++ b/test/e2e_flags.go @@ -55,6 +55,7 @@ var ServingFlags = initializeServingFlags() // ServingEnvironmentFlags holds the e2e flags needed only by the serving repo. type ServingEnvironmentFlags struct { ResolvableDomain bool // Resolve Route controller's `domainSuffix` + Https bool // Indicates where the test service will be created with https } // initializeServingFlags registers flags used by e2e tests, calling flag.Parse() here would fail in @@ -64,6 +65,8 @@ func initializeServingFlags() *ServingEnvironmentFlags { flag.BoolVar(&f.ResolvableDomain, "resolvabledomain", false, "Set this flag to true if you have configured the `domainSuffix` on your Route controller to a domain that will resolve to your test cluster.") + flag.BoolVar(&f.Https, "https", false, + "Set this flag to true to run all tests with https.") flag.Set("alsologtostderr", "true") logging.InitializeLogger(test.Flags.LogVerbose) diff --git a/test/performance/latency_test.go b/test/performance/latency_test.go index 038043063e73..fbe88c5e6398 100644 --- a/test/performance/latency_test.go +++ b/test/performance/latency_test.go @@ -64,7 +64,8 @@ func timeToServe(t *testing.T, img, query string, reqTimeout time.Duration) { test.CleanupOnInterrupt(func() { TearDown(perfClients, names, t.Logf) }) t.Log("Creating a new Service") - objs, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names) + objs, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */) if err != nil { t.Fatalf("Failed to create Service: %v", err) } diff --git a/test/performance/observed_concurency_test.go b/test/performance/observed_concurency_test.go index 1e48e17ffb1f..da06e23aebbb 100644 --- a/test/performance/observed_concurency_test.go +++ b/test/performance/observed_concurency_test.go @@ -152,7 +152,8 @@ func testConcurrencyN(t *testing.T, concurrency int) []junit.TestCase { test.CleanupOnInterrupt(func() { TearDown(perfClients, names, t.Logf) }) t.Log("Creating a new Service") - objs, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + objs, _, err := v1a1test.CreateRunLatestServiceReady(t, clients, &names, + false /* https TODO(taragu) turn this on after helloworld test running with https */, v1a1opts.WithResourceRequirements(corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("10m"), diff --git a/test/performance/scale_from_zero_test.go b/test/performance/scale_from_zero_test.go index 4dabcddf5ec0..e72745b3e144 100644 --- a/test/performance/scale_from_zero_test.go +++ b/test/performance/scale_from_zero_test.go @@ -131,8 +131,10 @@ func createServices(t *testing.T, pc *Client, count int) ([]*v1a1test.ResourceOb ndx := i g.Go(func() error { var err error - if objs[ndx], err = v1a1test.CreateRunLatestServiceReady(t, pc.E2EClients, testNames[ndx], sos...); err != nil { - return fmt.Errorf("%02d: failed to create Ready service: %w", ndx, err) + if objs[ndx], _, err = v1a1test.CreateRunLatestServiceReady(t, pc.E2EClients, testNames[ndx], + false /* https TODO(taragu) turn this on after helloworld test running with https */, + sos...); err != nil { + return fmt.Errorf("%02d: failed to create Ready service: %v", ndx, err) } return nil }) diff --git a/test/v1alpha1/service.go b/test/v1alpha1/service.go index ef2c464a1965..8096d774a1d1 100644 --- a/test/v1alpha1/service.go +++ b/test/v1alpha1/service.go @@ -19,10 +19,28 @@ limitations under the License. package v1alpha1 import ( + "bytes" "context" + "crypto/rand" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" "encoding/json" + "encoding/pem" + "errors" "fmt" + "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/watch" + "knative.dev/pkg/apis/istio/v1alpha3" + "knative.dev/pkg/test/spoof" + "math/big" + "net" + "net/http" + "strings" + "sync" "testing" + "time" "github.com/mattbaird/jsonpatch" corev1 "k8s.io/api/core/v1" @@ -38,6 +56,17 @@ import ( "knative.dev/serving/test" ) +const ( + // Namespace is the namespace of the ingress gateway + Namespace = "knative-serving" + + // GatewayName is the name of the ingress gateway + GatewayName = "knative-ingress-gateway" +) +var ( + domainName *string +) + func validateCreatedServiceStatus(clients *test.Clients, names *test.ResourceNames) error { return CheckServiceState(clients.ServingAlphaClient, names.Service, func(s *v1alpha1.Service) (bool, error) { if s.Status.URL == nil || s.Status.URL.Host == "" { @@ -90,16 +119,41 @@ func GetResourceObjects(clients *test.Clients, names test.ResourceNames) (*Resou // CreateRunLatestServiceReady creates a new Service in state 'Ready'. This function expects Service and Image name passed in through 'names'. // Names is updated with the Route and Configuration created by the Service and ResourceObjects is returned with the Service, Route, and Configuration objects. +// If this function is called with https == true, the gateway MUST be restored afterwards. // Returns error if the service does not come up correctly. -func CreateRunLatestServiceReady(t *testing.T, clients *test.Clients, names *test.ResourceNames, fopt ...rtesting.ServiceOption) (*ResourceObjects, error) { +func CreateRunLatestServiceReady(t *testing.T, clients *test.Clients, names *test.ResourceNames, https bool, fopt ...rtesting.ServiceOption) (*ResourceObjects, *spoof.TransportOption, error) { if names.Image == "" { - return nil, fmt.Errorf("expected non-empty Image name; got Image=%v", names.Image) + return nil, nil, fmt.Errorf("expected non-empty Image name; got Image=%v", names.Image) + } + + var httpsTransportOption *spoof.TransportOption + var err error + if https { + tlsOptions := &v1alpha3.TLSOptions{ + Mode: v1alpha3.TLSModeSimple, + PrivateKey: "/etc/istio/ingressgateway-certs/tls.key", + ServerCertificate: "/etc/istio/ingressgateway-certs/tls.crt", + } + servers := []v1alpha3.Server{{ + Hosts: []string{"*"}, + Port: v1alpha3.Port{ + Name: "standard-https", + Number: 443, + Protocol: v1alpha3.ProtocolHTTPS, + }, + TLS: tlsOptions, + }} + httpsTransportOption, err = setupHTTPS(t, clients.KubeClient, names.Service, GetDomain(t, clients)) + if err != nil { + return nil, nil, err + } + setupGateway(t, clients, servers) } t.Logf("Creating a new Service %s.", names.Service) svc, err := CreateLatestService(t, clients, *names, fopt...) if err != nil { - return nil, err + return nil, httpsTransportOption, err } // Populate Route and Configuration Objects with name @@ -113,13 +167,13 @@ func CreateRunLatestServiceReady(t *testing.T, clients *test.Clients, names *tes t.Logf("Waiting for Service %q to transition to Ready.", names.Service) if err := WaitForServiceState(clients.ServingAlphaClient, names.Service, IsServiceReady, "ServiceIsReady"); err != nil { - return nil, err + return nil, httpsTransportOption, err } t.Log("Checking to ensure Service Status is populated for Ready service", names.Service) err = validateCreatedServiceStatus(clients, names) if err != nil { - return nil, err + return nil, httpsTransportOption, err } t.Log("Getting latest objects Created by Service", names.Service) @@ -127,7 +181,7 @@ func CreateRunLatestServiceReady(t *testing.T, clients *test.Clients, names *tes if err == nil { t.Log("Successfully created Service", names.Service) } - return resources, err + return resources, httpsTransportOption, err } // CreateRunLatestServiceLegacyReady creates a new Service in state 'Ready'. This function expects Service and Image name passed in through 'names'. @@ -344,3 +398,198 @@ func IsServiceRoutesNotReady(s *v1alpha1.Service) (bool, error) { result := s.Status.GetCondition(v1alpha1.ServiceConditionRoutesReady) return s.Generation == s.Status.ObservedGeneration && result != nil && result.Status == corev1.ConditionFalse, nil } + +// RestoreGateway updates the gateway object to the oldGateway +func RestoreGateway(t *testing.T, clients *test.Clients, oldGateway v1alpha3.Gateway) { + currGateway, err := clients.SharedClient.NetworkingV1alpha3().Gateways(Namespace).Get(GatewayName, metav1.GetOptions{}) + if err != nil { + t.Fatalf("Failed to get Gateway %s/%s", Namespace, GatewayName) + } + if equality.Semantic.DeepEqual(*currGateway, oldGateway) { + t.Log("Gateway not restored because it's still the same") + return + } + currGateway.Spec.Servers = oldGateway.Spec.Servers + if _, err := clients.SharedClient.NetworkingV1alpha3().Gateways(Namespace).Update(currGateway); err != nil { + t.Fatalf("Failed to restore Gateway %s/%s: %v", Namespace, GatewayName, err) + } +} + +// GetDomain returns the domain name. If the saved domain name is null, it will create a dummy service in order to get +// the domain name +func GetDomain(t *testing.T, clients *test.Clients) string { + if domainName == nil { + names := test.ResourceNames{ + Service: test.ObjectNameForTest(t), + Image: "helloworld", + } + test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) + defer test.TearDown(clients, names) + objects, _, err := CreateRunLatestServiceReady(t, clients, &names, false /* https */) + if err != nil { + t.Fatalf("Failed to create Service %s: %v", names.Service, err) + } + domainName = &(strings.SplitN(objects.Route.Status.URL.Host, ".", 2)[1]) + } + return *domainName +} + +// setupGateway updates the ingress Gateway to the provided Servers and waits until all Envoy pods have been updated. +func setupGateway(t *testing.T, clients *test.Clients, servers []v1alpha3.Server) { + // Get the current Gateway + curGateway, err := clients.SharedClient.NetworkingV1alpha3().Gateways(Namespace).Get(GatewayName, metav1.GetOptions{}) + if err != nil { + t.Fatalf("Failed to get Gateway %s/%s: %v", Namespace, GatewayName, err) + } + + // Update its Spec + newGateway := curGateway.DeepCopy() + newGateway.Spec.Servers = servers + + // Update the Gateway + gw, err := clients.SharedClient.NetworkingV1alpha3().Gateways(Namespace).Update(newGateway) + if err != nil { + t.Fatalf("Failed to update Gateway %s/%s: %v", Namespace, GatewayName, err) + } + + var selectors []string + for k, v := range gw.Spec.Selector { + selectors = append(selectors, k+"="+v) + } + selector := strings.Join(selectors, ",") + + // Restart the Gateway pods: this is needed because Istio without SDS won't refresh the cert when the secret is updated + pods, err := clients.KubeClient.Kube.CoreV1().Pods("istio-system").List(metav1.ListOptions{LabelSelector: selector}) + if err != nil { + t.Fatalf("Failed to list Gateway pods: %v", err) + } + + // TODO(bancel): there is a race condition here if a pod listed in the call above is deleted before calling watch below + + var wg sync.WaitGroup + wg.Add(len(pods.Items)) + wtch, err := clients.KubeClient.Kube.CoreV1().Pods("istio-system").Watch(metav1.ListOptions{LabelSelector: selector}) + if err != nil { + t.Fatalf("Failed to watch Gateway pods: %v", err) + } + defer wtch.Stop() + + done := make(chan struct{}) + go func() { + for { + select { + case event := <-wtch.ResultChan(): + if event.Type == watch.Deleted { + wg.Done() + } + case <-done: + return + } + } + }() + + err = clients.KubeClient.Kube.CoreV1().Pods("istio-system").DeleteCollection(&metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: selector}) + if err != nil { + t.Fatalf("Failed to delete Gateway pods: %v", err) + } + + wg.Wait() + done <- struct{}{} +} + +// setupHTTPS creates a self-signed certificate, installs it as a Secret and returns an *http.Transport +// trusting the certificate as a root CA. +func setupHTTPS(t *testing.T, kubeClient *ptest.KubeClient, serviceName, domain string) (*spoof.TransportOption, error) { + t.Helper() + hosts := []string{serviceName + "." + domain} + cert, key, err := generateCertificate(hosts) + if err != nil { + return nil, err + } + + rootCAs, _ := x509.SystemCertPool() + if rootCAs == nil { + rootCAs = x509.NewCertPool() + } + + if ok := rootCAs.AppendCertsFromPEM(cert); !ok { + return nil, errors.New("failed to add the certificate to the root CA") + } + + kubeClient.Kube.CoreV1().Secrets("istio-system").Delete("istio-ingressgateway-certs", &metav1.DeleteOptions{}) + _, err = kubeClient.Kube.CoreV1().Secrets("istio-system").Create(&corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "istio-system", + Name: "istio-ingressgateway-certs", + }, + Type: corev1.SecretTypeTLS, + Data: map[string][]byte{ + "tls.key": key, + "tls.crt": cert, + }, + }) + if err != nil { + return nil, err + } + var transportOption spoof.TransportOption = func(transport *http.Transport) *http.Transport { + transport.TLSClientConfig = &tls.Config{RootCAs: rootCAs} + return transport + } + return &transportOption, nil +} + +// generateCertificate generates a self-signed certificate for the provided hosts and returns +// the PEM encoded certificate and private key. +func generateCertificate(hosts []string) ([]byte, []byte, error) { + priv, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return nil, nil, fmt.Errorf("failed to generate private key: %v", err) + } + + notBefore := time.Now().Add(-5 * time.Minute) + notAfter := notBefore.Add(2 * time.Hour) + + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + if err != nil { + return nil, nil, fmt.Errorf("failed to generate serial number: %v", err) + } + + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + Organization: []string{"Knative Serving"}, + }, + NotBefore: notBefore, + NotAfter: notAfter, + + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + for _, h := range hosts { + if ip := net.ParseIP(h); ip != nil { + template.IPAddresses = append(template.IPAddresses, ip) + } else { + template.DNSNames = append(template.DNSNames, h) + } + } + + derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) + if err != nil { + return nil, nil, fmt.Errorf("failed to create the certificate: %v", err) + } + + var certBuf bytes.Buffer + if err := pem.Encode(&certBuf, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { + return nil, nil, fmt.Errorf("failed to encode the certificate: %v", err) + } + + var keyBuf bytes.Buffer + if err := pem.Encode(&keyBuf, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil { + return nil, nil, fmt.Errorf("failed to encode the private key: %v", err) + } + + return certBuf.Bytes(), keyBuf.Bytes(), nil +} From 72501eed94be585c3d9060af4eabf2183b480185 Mon Sep 17 00:00:00 2001 From: Tara Gu Date: Tue, 5 Nov 2019 17:16:41 -0500 Subject: [PATCH 2/3] Remove GetDomain --- test/v1alpha1/service.go | 75 +++++++++++++++------------------------- 1 file changed, 28 insertions(+), 47 deletions(-) diff --git a/test/v1alpha1/service.go b/test/v1alpha1/service.go index 8096d774a1d1..ba943993e358 100644 --- a/test/v1alpha1/service.go +++ b/test/v1alpha1/service.go @@ -126,34 +126,10 @@ func CreateRunLatestServiceReady(t *testing.T, clients *test.Clients, names *tes return nil, nil, fmt.Errorf("expected non-empty Image name; got Image=%v", names.Image) } - var httpsTransportOption *spoof.TransportOption - var err error - if https { - tlsOptions := &v1alpha3.TLSOptions{ - Mode: v1alpha3.TLSModeSimple, - PrivateKey: "/etc/istio/ingressgateway-certs/tls.key", - ServerCertificate: "/etc/istio/ingressgateway-certs/tls.crt", - } - servers := []v1alpha3.Server{{ - Hosts: []string{"*"}, - Port: v1alpha3.Port{ - Name: "standard-https", - Number: 443, - Protocol: v1alpha3.ProtocolHTTPS, - }, - TLS: tlsOptions, - }} - httpsTransportOption, err = setupHTTPS(t, clients.KubeClient, names.Service, GetDomain(t, clients)) - if err != nil { - return nil, nil, err - } - setupGateway(t, clients, servers) - } - t.Logf("Creating a new Service %s.", names.Service) svc, err := CreateLatestService(t, clients, *names, fopt...) if err != nil { - return nil, httpsTransportOption, err + return nil, nil, err } // Populate Route and Configuration Objects with name @@ -166,14 +142,38 @@ func CreateRunLatestServiceReady(t *testing.T, clients *test.Clients, names *tes } t.Logf("Waiting for Service %q to transition to Ready.", names.Service) - if err := WaitForServiceState(clients.ServingAlphaClient, names.Service, IsServiceReady, "ServiceIsReady"); err != nil { - return nil, httpsTransportOption, err + if err = WaitForServiceState(clients.ServingAlphaClient, names.Service, IsServiceReady, "ServiceIsReady"); err != nil { + return nil, nil, err } t.Log("Checking to ensure Service Status is populated for Ready service", names.Service) err = validateCreatedServiceStatus(clients, names) if err != nil { - return nil, httpsTransportOption, err + return nil, nil, err + } + + var httpsTransportOption *spoof.TransportOption + if https { + tlsOptions := &v1alpha3.TLSOptions{ + Mode: v1alpha3.TLSModeSimple, + PrivateKey: "/etc/istio/ingressgateway-certs/tls.key", + ServerCertificate: "/etc/istio/ingressgateway-certs/tls.crt", + } + servers := []v1alpha3.Server{{ + Hosts: []string{"*"}, + Port: v1alpha3.Port{ + Name: "standard-https", + Number: 443, + Protocol: v1alpha3.ProtocolHTTPS, + }, + TLS: tlsOptions, + }} + domainName := strings.SplitN(names.URL.Host, ".", 2)[1] + httpsTransportOption, err = setupHTTPS(t, clients.KubeClient, names.Service, domainName) + if err != nil { + return nil, nil, err + } + setupGateway(t, clients, servers) } t.Log("Getting latest objects Created by Service", names.Service) @@ -415,25 +415,6 @@ func RestoreGateway(t *testing.T, clients *test.Clients, oldGateway v1alpha3.Gat } } -// GetDomain returns the domain name. If the saved domain name is null, it will create a dummy service in order to get -// the domain name -func GetDomain(t *testing.T, clients *test.Clients) string { - if domainName == nil { - names := test.ResourceNames{ - Service: test.ObjectNameForTest(t), - Image: "helloworld", - } - test.CleanupOnInterrupt(func() { test.TearDown(clients, names) }) - defer test.TearDown(clients, names) - objects, _, err := CreateRunLatestServiceReady(t, clients, &names, false /* https */) - if err != nil { - t.Fatalf("Failed to create Service %s: %v", names.Service, err) - } - domainName = &(strings.SplitN(objects.Route.Status.URL.Host, ".", 2)[1]) - } - return *domainName -} - // setupGateway updates the ingress Gateway to the provided Servers and waits until all Envoy pods have been updated. func setupGateway(t *testing.T, clients *test.Clients, servers []v1alpha3.Server) { // Get the current Gateway From 84fd9cd9d2c203550777e8a18cbc2786e2fd9cf2 Mon Sep 17 00:00:00 2001 From: Tara Gu Date: Wed, 6 Nov 2019 14:31:49 -0500 Subject: [PATCH 3/3] More simplification --- test/v1alpha1/service.go | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/test/v1alpha1/service.go b/test/v1alpha1/service.go index ba943993e358..60be8b01d0b3 100644 --- a/test/v1alpha1/service.go +++ b/test/v1alpha1/service.go @@ -168,8 +168,7 @@ func CreateRunLatestServiceReady(t *testing.T, clients *test.Clients, names *tes }, TLS: tlsOptions, }} - domainName := strings.SplitN(names.URL.Host, ".", 2)[1] - httpsTransportOption, err = setupHTTPS(t, clients.KubeClient, names.Service, domainName) + httpsTransportOption, err = setupHTTPS(t, clients.KubeClient, names.URL.Host) if err != nil { return nil, nil, err } @@ -480,10 +479,9 @@ func setupGateway(t *testing.T, clients *test.Clients, servers []v1alpha3.Server // setupHTTPS creates a self-signed certificate, installs it as a Secret and returns an *http.Transport // trusting the certificate as a root CA. -func setupHTTPS(t *testing.T, kubeClient *ptest.KubeClient, serviceName, domain string) (*spoof.TransportOption, error) { +func setupHTTPS(t *testing.T, kubeClient *ptest.KubeClient, host string) (*spoof.TransportOption, error) { t.Helper() - hosts := []string{serviceName + "." + domain} - cert, key, err := generateCertificate(hosts) + cert, key, err := generateCertificate(host) if err != nil { return nil, err } @@ -519,9 +517,9 @@ func setupHTTPS(t *testing.T, kubeClient *ptest.KubeClient, serviceName, domain return &transportOption, nil } -// generateCertificate generates a self-signed certificate for the provided hosts and returns +// generateCertificate generates a self-signed certificate for the provided host and returns // the PEM encoded certificate and private key. -func generateCertificate(hosts []string) ([]byte, []byte, error) { +func generateCertificate(host string) ([]byte, []byte, error) { priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return nil, nil, fmt.Errorf("failed to generate private key: %v", err) @@ -549,12 +547,10 @@ func generateCertificate(hosts []string) ([]byte, []byte, error) { BasicConstraintsValid: true, } - for _, h := range hosts { - if ip := net.ParseIP(h); ip != nil { - template.IPAddresses = append(template.IPAddresses, ip) - } else { - template.DNSNames = append(template.DNSNames, h) - } + if ip := net.ParseIP(host); ip != nil { + template.IPAddresses = append(template.IPAddresses, ip) + } else { + template.DNSNames = append(template.DNSNames, host) } derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)