diff --git a/acceptance/go.mod b/acceptance/go.mod index 8be66a29da..7a8cc6de8c 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -4,13 +4,13 @@ go 1.20 replace github.com/hashicorp/consul/sdk => github.com/hashicorp/consul/sdk v0.4.1-0.20231213150639-123bc95e1a3f -replace github.com/hashicorp/consul/proto-public => github.com/hashicorp/consul/proto-public v0.1.2-0.20231212195019-69e3f93ee8a3 +replace github.com/hashicorp/consul/proto-public => github.com/hashicorp/consul/proto-public v0.1.2-0.20240129174413-a2d50af1bdfb require ( github.com/google/uuid v1.3.0 github.com/gruntwork-io/terratest v0.31.2 - github.com/hashicorp/consul-k8s/control-plane v0.0.0-20230609143603-198c4433d892 - github.com/hashicorp/consul/api v1.10.1-0.20230906155245-56917eb4c968 + github.com/hashicorp/consul-k8s/control-plane v0.0.0-20240201210635-25708a18e4aa + github.com/hashicorp/consul/api v1.10.1-0.20240122152324-758ddf84e9c9 github.com/hashicorp/consul/proto-public v0.5.1 github.com/hashicorp/consul/sdk v0.15.0 github.com/hashicorp/go-multierror v1.1.1 @@ -47,7 +47,7 @@ require ( github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect - github.com/fatih/color v1.14.1 // indirect + github.com/fatih/color v1.15.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-logr/logr v1.2.4 // indirect @@ -94,7 +94,7 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect github.com/miekg/dns v1.1.50 // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect diff --git a/acceptance/go.sum b/acceptance/go.sum index 36713f97e1..5dab27228c 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -106,8 +106,10 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -182,8 +184,8 @@ github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2Vvl github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= -github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -391,12 +393,13 @@ github.com/gruntwork-io/gruntwork-cli v0.7.0 h1:YgSAmfCj9c61H+zuvHwKfYUwlMhu5arn github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= github.com/gruntwork-io/terratest v0.31.2 h1:xvYHA80MUq5kx670dM18HInewOrrQrAN+XbVVtytUHg= github.com/gruntwork-io/terratest v0.31.2/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= -github.com/hashicorp/consul-k8s/control-plane v0.0.0-20230609143603-198c4433d892 h1:4iI0ztWbVPTSDax+m1/XDs4jIRorxY4kSMyuM0fX+Dc= -github.com/hashicorp/consul-k8s/control-plane v0.0.0-20230609143603-198c4433d892/go.mod h1:iZ8BJGSnY52wnxJTo2VIfGX63CPjqiNzbuqdOtJCKnI= -github.com/hashicorp/consul/api v1.10.1-0.20230906155245-56917eb4c968 h1:lQ7QmlL0N4/ftLBex8n73Raji29o7EVssqCoeeczKac= -github.com/hashicorp/consul/api v1.10.1-0.20230906155245-56917eb4c968/go.mod h1:NZJGRFYruc/80wYowkPFCp1LbGmJC9L8izrwfyVx/Wg= -github.com/hashicorp/consul/proto-public v0.1.2-0.20231212195019-69e3f93ee8a3 h1:FFRKi+IpoXHwXZDgqG+BNAG1duAuokbzm+5b2pcY1us= -github.com/hashicorp/consul/proto-public v0.1.2-0.20231212195019-69e3f93ee8a3/go.mod h1:fCFq3EfW2Iwu5her/hgqVqcJikY8nBtDiKFgfOdBvvw= +github.com/hashicorp/consul-k8s/control-plane v0.0.0-20240201210635-25708a18e4aa h1:T9u/mKHEqqQvv8jJ3+S4cLj9sn7KDMSW+n4Uc8YlVos= +github.com/hashicorp/consul-k8s/control-plane v0.0.0-20240201210635-25708a18e4aa/go.mod h1:Yj8VIjM3SElLcOVTkjy/A0igua8XBuhteYuQ1O84FDY= +github.com/hashicorp/consul-server-connection-manager v0.1.6 h1:ktj8Fi+dRXn9hhM+FXsfEJayhzzgTqfH08Ne5M6Fmug= +github.com/hashicorp/consul/api v1.10.1-0.20240122152324-758ddf84e9c9 h1:qaS6rE768dt5hGPl2y4DIABXF4eA23BNSmWFpEr3kWQ= +github.com/hashicorp/consul/api v1.10.1-0.20240122152324-758ddf84e9c9/go.mod h1:gInwZGrnWlE1Vvq6rSD5pUf6qwNa69NTLLknbdwQRUk= +github.com/hashicorp/consul/proto-public v0.1.2-0.20240129174413-a2d50af1bdfb h1:4LCdNw3DTe5WRe3fJvY+hkRLNtRlunl/9PJuOlQmPa8= +github.com/hashicorp/consul/proto-public v0.1.2-0.20240129174413-a2d50af1bdfb/go.mod h1:ar/M/Gv31GeE7DxektZgAydwsCiOf6sBeJFcjQVTlVs= github.com/hashicorp/consul/sdk v0.4.1-0.20231213150639-123bc95e1a3f h1:GKsa7bfoL7xgvCkzYJMF9eYYNfLWQyk8QuRZZl4nMTo= github.com/hashicorp/consul/sdk v0.4.1-0.20231213150639-123bc95e1a3f/go.mod h1:r/OmRRPbHOe0yxNahLw7G9x5WG17E1BIECMtCjcPSNo= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -420,6 +423,7 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-netaddrs v0.1.0 h1:TnlYvODD4C/wO+j7cX1z69kV5gOzI87u3OcUinANaW8= github.com/hashicorp/go-plugin v1.4.5 h1:oTE/oQR4eghggRg8VY7PAz3dr++VwDNBGCcOfIvHpBo= github.com/hashicorp/go-plugin v1.4.5/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= @@ -543,8 +547,8 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= @@ -979,6 +983,7 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/acceptance/tests/api-gateway_v2/api_gateway_v2_test.go b/acceptance/tests/api-gateway_v2/api_gateway_v2_test.go new file mode 100644 index 0000000000..1e01584e32 --- /dev/null +++ b/acceptance/tests/api-gateway_v2/api_gateway_v2_test.go @@ -0,0 +1,186 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package apigatewayv2 + +import ( + "context" + "encoding/base64" + "fmt" + "strconv" + "testing" + "time" + + "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/sdk/testutil/retry" + + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" + meshv2beta1 "github.com/hashicorp/consul-k8s/control-plane/api/mesh/v2beta1" + + "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/types" +) + +// Test that api gateway basic functionality works in a default installation and a secure installation for V2. +func TestAPIGateway_V2_Basic(t *testing.T) { + + cases := []struct { + secure bool + }{ + { + secure: false, + }, + { + secure: true, + }, + } + for _, c := range cases { + name := fmt.Sprintf("secure: %t", c.secure) + t.Run(name, func(t *testing.T) { + ctx := suite.Environment().DefaultContext(t) + cfg := suite.Config() + helmValues := map[string]string{ + "connectInject.enabled": "true", + "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), + "global.tls.enabled": strconv.FormatBool(c.secure), + "global.logLevel": "trace", + "global.experiments[0]": "resource-apis", + } + + releaseName := helpers.RandomName() + consulCluster := consul.NewHelmCluster(t, helmValues, ctx, cfg, releaseName) + + consulCluster.Create(t) + + // Override the default proxy config settings for this test + consulClient, _ := consulCluster.SetupConsulClient(t, c.secure) + _, _, err := consulClient.ConfigEntries().Set(&api.ProxyConfigEntry{ + Kind: api.ProxyDefaults, + Name: api.ProxyConfigGlobal, + Config: map[string]interface{}{ + "protocol": "http", + }, + }, nil) + require.NoError(t, err) + + logger.Log(t, "creating api-gateway resources") + out, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "apply", "-k", "../fixtures/bases/api-gateway-v2") + require.NoError(t, err, out) + helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + // Ignore errors here because if the test ran as expected + // the custom resources will have been deleted. + k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "delete", "-k", "../fixtures/bases/api-gateway-v2") + }) + + // Create certificate secret, we do this separately since + // applying the secret will make an invalid certificate that breaks other tests + logger.Log(t, "creating certificate secret") + out, err = k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "apply", "-f", "../fixtures/bases/api-gateway-v2/certificate.yaml") + require.NoError(t, err, out) + helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + // Ignore errors here because if the test ran as expected + // the custom resources will have been deleted. + k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "delete", "-f", "../fixtures/bases/api-gateway-v2/certificate.yaml") + }) + + // patch certificate with data + logger.Log(t, "patching certificate secret with generated data") + certificate := generateCertificate(t, nil, "gateway.test.local") + k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "secret", "certificate", "-p", fmt.Sprintf(`{"data":{"tls.crt":"%s","tls.key":"%s"}}`, base64.StdEncoding.EncodeToString(certificate.CertPEM), base64.StdEncoding.EncodeToString(certificate.PrivateKeyPEM)), "--type=merge") + + // We use the static-client pod so that we can make calls to the api gateway + // via kubectl exec without needing a route into the cluster from the test machine. + logger.Log(t, "creating static-client pod") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-client") + + logger.Log(t, "creating target tcp server") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.NoCleanup, cfg.DebugDirectory, "../fixtures/bases/static-server-tcp") + + logger.Log(t, "creating tcp-route") + k8s.RunKubectl(t, ctx.KubectlOptions(t), "apply", "-f", "../fixtures/cases/api-gateways-v2/tcproute/route.yaml") + helpers.Cleanup(t, cfg.NoCleanupOnFailure, cfg.NoCleanup, func() { + // Ignore errors here because if the test ran as expected + // the custom resources will have been deleted. + k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "delete", "-f", "../fixtures/cases/api-gateways-v2/tcproute/route.yaml") + }) + + // Grab a kubernetes client so that we can verify binding + // behavior prior to issuing requests through the gateway. + k8sClient := ctx.ControllerRuntimeClient(t) + + // On startup, the controller can take upwards of 1m to perform + // leader election so we may need to wait a long time for + // the reconcile loop to run (hence the timeout here). + var gatewayAddress string + counter := &retry.Counter{Count: 120, Wait: 2 * time.Second} + retry.RunWith(counter, t, func(r *retry.R) { + var gateway meshv2beta1.APIGateway + err := k8sClient.Get(context.Background(), types.NamespacedName{Name: "gateway", Namespace: "default"}, &gateway) + require.NoError(r, err) + + // check our finalizers + require.Len(r, gateway.Finalizers, 1) + require.EqualValues(r, gatewayFinalizer, gateway.Finalizers()[0]) + + // check our statuses + checkV2StatusCondition(r, gateway.APIGatewayStatus.Conditions, trueV2Condition("Accepted", "Accepted")) + checkV2StatusCondition(r, gateway.APIGatewayStatus.Conditions, trueV2Condition("ConsulAccepted", "Accepted")) + require.Len(r, gateway.APIGatewayStatus.Listeners, 3) + + require.EqualValues(r, 1, gateway.APIGatewayStatus.Listeners[0].AttachedRoutes) + checkV2StatusCondition(r, gateway.APIGatewayStatus.Listeners[0].Conditions, trueV2Condition("Accepted", "Accepted")) + checkV2StatusCondition(r, gateway.APIGatewayStatus.Listeners[0].Conditions, falseV2Condition("Conflicted", "NoConflicts")) + checkV2StatusCondition(r, gateway.APIGatewayStatus.Listeners[0].Conditions, trueV2Condition("ResolvedRefs", "ResolvedRefs")) + require.EqualValues(r, 1, gateway.APIGatewayStatus.Listeners[1].AttachedRoutes) + checkV2StatusCondition(r, gateway.APIGatewayStatus.Listeners[1].Conditions, trueV2Condition("Accepted", "Accepted")) + checkV2StatusCondition(r, gateway.APIGatewayStatus.Listeners[1].Conditions, falseV2Condition("Conflicted", "NoConflicts")) + checkV2StatusCondition(r, gateway.APIGatewayStatus.Listeners[1].Conditions, trueV2Condition("ResolvedRefs", "ResolvedRefs")) + require.EqualValues(r, 1, gateway.APIGatewayStatus.Listeners[2].AttachedRoutes) + checkV2StatusCondition(r, gateway.APIGatewayStatus.Listeners[2].Conditions, trueV2Condition("Accepted", "Accepted")) + checkV2StatusCondition(r, gateway.APIGatewayStatus.Listeners[2].Conditions, falseV2Condition("Conflicted", "NoConflicts")) + checkV2StatusCondition(r, gateway.APIGatewayStatus.Listeners[2].Conditions, trueV2Condition("ResolvedRefs", "ResolvedRefs")) + + // check that we have an address to use + require.Len(r, gateway.APIGatewayStatus.Addresses, 1) + // now we know we have an address, set it so we can use it + gatewayAddress = gateway.APIGatewayStatus.Addresses[0].Value + }) + + // now that we've satisfied those assertions, we know reconciliation is done + // so we can run assertions on the routes and the other objects + + // gateway class checks + var gatewayClass meshv2beta1.GatewayClass + err = k8sClient.Get(context.Background(), types.NamespacedName{Name: "gateway-class"}, &gatewayClass) + require.NoError(t, err) + + // check our finalizers + require.Len(t, gatewayClass.Finalizers, 1) + require.EqualValues(t, gatewayClassFinalizer, gatewayClass.Finalizers()[0]) + + // tcp route checks + var tcpRoute meshv2beta1.TCPRoute + err = k8sClient.Get(context.Background(), types.NamespacedName{Name: "tcp-route", Namespace: "default"}, &tcpRoute) + require.NoError(t, err) + + // check our finalizers + require.Len(t, tcpRoute.Finalizers, 1) + require.EqualValues(t, gatewayFinalizer, tcpRoute.Finalizers()[0]) + + // TODO check values actually created in the resource API + + // finally we check that we can actually route to the service via the gateway + k8sOptions := ctx.KubectlOptions(t) + targetTCPAddress := fmt.Sprintf("http://%s:81", gatewayAddress) + + // Test that we can make a call to the api gateway + // via the static-client pod. It should route to the static-server pod. + logger.Log(t, "trying calls to api gateway tcp") + k8s.CheckStaticServerConnectionSuccessful(t, k8sOptions, StaticClientName, targetTCPAddress) + + }) + } +} diff --git a/acceptance/tests/api-gateway_v2/helpers.go b/acceptance/tests/api-gateway_v2/helpers.go new file mode 100644 index 0000000000..124fa20450 --- /dev/null +++ b/acceptance/tests/api-gateway_v2/helpers.go @@ -0,0 +1,123 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package apigatewayv2 + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + meshv2beta1 "github.com/hashicorp/consul-k8s/control-plane/api/mesh/v2beta1" + corev1 "k8s.io/api/core/v1" + "math/big" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +const ( + StaticClientName = "static-client" + gatewayClassControllerName = "mesh.consul.hashicorp.com/gateway-controller" + //TODO these values will likely need to be update to their V2 values for the test to pass. + gatewayClassFinalizer = "gateway-exists-finalizer.consul.hashicorp.com" + gatewayFinalizer = "gateway-finalizer.consul.hashicorp.com" +) + +type certificateInfo struct { + Cert *x509.Certificate + PrivateKey *rsa.PrivateKey + CertPEM []byte + PrivateKeyPEM []byte +} + +func checkV2StatusCondition(t require.TestingT, conditions []meshv2beta1.Condition, toCheck meshv2beta1.Condition) { + for _, c := range conditions { + if c.Type == toCheck.Type { + require.EqualValues(t, toCheck.Reason, c.Reason) + require.EqualValues(t, toCheck.Status, c.Status) + return + } + } + + t.Errorf("expected condition not found: %s", toCheck.Type) +} + +func trueV2Condition(conditionType, reason string) meshv2beta1.Condition { + return meshv2beta1.Condition{ + Type: meshv2beta1.ConditionType(conditionType), + Reason: reason, + Status: corev1.ConditionTrue, + } +} + +func falseV2Condition(conditionType, reason string) meshv2beta1.Condition { + return meshv2beta1.Condition{ + Type: meshv2beta1.ConditionType(conditionType), + Reason: reason, + Status: corev1.ConditionFalse, + } +} + +func generateCertificate(t *testing.T, ca *certificateInfo, commonName string) *certificateInfo { + t.Helper() + + bits := 2048 + privateKey, err := rsa.GenerateKey(rand.Reader, bits) + require.NoError(t, err) + + usage := x509.KeyUsageDigitalSignature + if ca == nil { + usage = x509.KeyUsageCertSign + } + + expiration := time.Now().AddDate(10, 0, 0) + cert := &x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + Organization: []string{"Testing, INC."}, + Country: []string{"US"}, + Province: []string{""}, + Locality: []string{"San Francisco"}, + StreetAddress: []string{"Fake Street"}, + PostalCode: []string{"11111"}, + CommonName: commonName, + }, + IsCA: ca == nil, + NotBefore: time.Now().Add(-10 * time.Minute), + NotAfter: expiration, + SubjectKeyId: []byte{1, 2, 3, 4, 6}, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: usage, + BasicConstraintsValid: true, + } + caCert := cert + if ca != nil { + caCert = ca.Cert + } + caPrivateKey := privateKey + if ca != nil { + caPrivateKey = ca.PrivateKey + } + data, err := x509.CreateCertificate(rand.Reader, cert, caCert, &privateKey.PublicKey, caPrivateKey) + require.NoError(t, err) + + certBytes := pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", + Bytes: data, + }) + + privateKeyBytes := pem.EncodeToMemory(&pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(privateKey), + }) + + return &certificateInfo{ + Cert: cert, + CertPEM: certBytes, + PrivateKey: privateKey, + PrivateKeyPEM: privateKeyBytes, + } +} diff --git a/acceptance/tests/api-gateway_v2/main_test.go b/acceptance/tests/api-gateway_v2/main_test.go new file mode 100644 index 0000000000..47f4c3b3cf --- /dev/null +++ b/acceptance/tests/api-gateway_v2/main_test.go @@ -0,0 +1,24 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package apigatewayv2 + +import ( + "fmt" + "os" + "testing" + + testsuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" +) + +var suite testsuite.Suite + +func TestMain(m *testing.M) { + runTests := os.Getenv("TEST_APIGW_V2") + if runTests != "TRUE" { + fmt.Println("skipping") + os.Exit(0) + } + suite = testsuite.NewSuite(m) + os.Exit(suite.Run()) +} diff --git a/acceptance/tests/fixtures/bases/api-gateway-v2/apigateway.yaml b/acceptance/tests/fixtures/bases/api-gateway-v2/apigateway.yaml new file mode 100644 index 0000000000..c4fa0d6364 --- /dev/null +++ b/acceptance/tests/fixtures/bases/api-gateway-v2/apigateway.yaml @@ -0,0 +1,16 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +apiVersion: mesh.consul.hashicorp.com/v2beta1 +kind: APIGateway +metadata: + name: gateway +spec: + gatewayClassName: gateway-class + listeners: + - protocol: TCP + port: 81 + name: tcp + allowedRoutes: + namespaces: + from: "All" diff --git a/acceptance/tests/fixtures/bases/api-gateway-v2/certificate.yaml b/acceptance/tests/fixtures/bases/api-gateway-v2/certificate.yaml new file mode 100644 index 0000000000..d35dc559e2 --- /dev/null +++ b/acceptance/tests/fixtures/bases/api-gateway-v2/certificate.yaml @@ -0,0 +1,11 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +apiVersion: v1 +kind: Secret +metadata: + name: certificate +type: kubernetes.io/tls +data: + tls.crt: "" + tls.key: "" \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/api-gateway-v2/gatewayclass.yaml b/acceptance/tests/fixtures/bases/api-gateway-v2/gatewayclass.yaml new file mode 100644 index 0000000000..583ffc210a --- /dev/null +++ b/acceptance/tests/fixtures/bases/api-gateway-v2/gatewayclass.yaml @@ -0,0 +1,13 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +apiVersion: mesh.consul.hashicorp.com/v2beta1 +kind: GatewayClass +metadata: + name: gateway-class +spec: + controllerName: "consul.hashicorp.com/gateway-controller" + parametersRef: + group: consul.hashicorp.com + kind: GatewayClassConfig + name: gateway-class-config diff --git a/acceptance/tests/fixtures/bases/api-gateway-v2/gatewayclassconfig.yaml b/acceptance/tests/fixtures/bases/api-gateway-v2/gatewayclassconfig.yaml new file mode 100644 index 0000000000..049cdd708f --- /dev/null +++ b/acceptance/tests/fixtures/bases/api-gateway-v2/gatewayclassconfig.yaml @@ -0,0 +1,7 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +apiVersion: mesh.consul.hashicorp.com/v2beta1 +kind: GatewayClassConfig +metadata: + name: gateway-class-config \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/api-gateway-v2/kustomization.yaml b/acceptance/tests/fixtures/bases/api-gateway-v2/kustomization.yaml new file mode 100644 index 0000000000..871949a1ab --- /dev/null +++ b/acceptance/tests/fixtures/bases/api-gateway-v2/kustomization.yaml @@ -0,0 +1,8 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +resources: + - gatewayclassconfig.yaml + - gatewayclass.yaml + - apigateway.yaml + - tcproute.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/api-gateway-v2/tcproute.yaml b/acceptance/tests/fixtures/bases/api-gateway-v2/tcproute.yaml new file mode 100644 index 0000000000..c06b0e4ee0 --- /dev/null +++ b/acceptance/tests/fixtures/bases/api-gateway-v2/tcproute.yaml @@ -0,0 +1,10 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +apiVersion: mesh.consul.hashicorp.com/v2beta1 +kind: TCPRoute +metadata: + name: tcp-route +spec: + parentRefs: + - name: gateway \ No newline at end of file