Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issues found in the nightly tests #1735

Merged
merged 10 commits into from
Nov 17, 2022
70 changes: 2 additions & 68 deletions acceptance/framework/consul/helm_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,18 @@ package consul
import (
"context"
"fmt"
"net"
"strings"
"testing"
"time"

"github.com/gruntwork-io/terratest/modules/helm"
terratestk8s "github.com/gruntwork-io/terratest/modules/k8s"
terratestLogger "github.com/gruntwork-io/terratest/modules/logger"
"github.com/hashicorp/consul-k8s/acceptance/framework/config"
"github.com/hashicorp/consul-k8s/acceptance/framework/environment"
"github.com/hashicorp/consul-k8s/acceptance/framework/helpers"
"github.com/hashicorp/consul-k8s/acceptance/framework/k8s"
"github.com/hashicorp/consul-k8s/acceptance/framework/logger"
"github.com/hashicorp/consul-k8s/acceptance/framework/portforward"
"github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/sdk/testutil/retry"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -303,72 +302,7 @@ func (h *HelmCluster) Upgrade(t *testing.T, helmValues map[string]string) {

func (h *HelmCluster) CreatePortForwardTunnel(t *testing.T, remotePort int) string {
serverPod := fmt.Sprintf("%s-consul-server-0", h.releaseName)
return h.CreatePortForwardTunnelToResourcePort(t, serverPod, remotePort)
}

func (h *HelmCluster) CreatePortForwardTunnelToResourcePort(t *testing.T, resourceName string, remotePort int) string {
localPort := terratestk8s.GetAvailablePort(t)
tunnel := terratestk8s.NewTunnelWithLogger(
h.helmOptions.KubectlOptions,
terratestk8s.ResourceTypePod,
resourceName,
localPort,
remotePort,
h.logger)

// Retry creating the port forward since it can fail occasionally.
retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 3}, t, func(r *retry.R) {
// NOTE: It's okay to pass in `t` to ForwardPortE despite being in a retry
// because we're using ForwardPortE (not ForwardPort) so the `t` won't
// get used to fail the test, just for logging.
require.NoError(r, tunnel.ForwardPortE(t))
})

doneChan := make(chan bool)

t.Cleanup(func() {
close(doneChan)
})

go h.monitorPortForwardedServer(t, localPort, tunnel, doneChan, resourceName, remotePort)

return fmt.Sprintf("127.0.0.1:%d", localPort)
}

func (h *HelmCluster) monitorPortForwardedServer(t *testing.T, port int, tunnel *terratestk8s.Tunnel, doneChan chan bool, resourceName string, remotePort int) {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()

for {
select {
case <-doneChan:
logger.Log(t, "stopping monitor of the port-forwarded server")
tunnel.Close()
return
case <-ticker.C:
conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", port))
if err != nil {
logger.Log(t, "lost connection to port-forwarded server; restarting port-forwarding", "port", port)
tunnel.Close()
tunnel = terratestk8s.NewTunnelWithLogger(
h.helmOptions.KubectlOptions,
terratestk8s.ResourceTypePod,
resourceName,
port,
remotePort,
h.logger)
err = tunnel.ForwardPortE(t)
if err != nil {
// If we couldn't establish a port forwarding channel, continue, so we can try again.
continue
}
}
if conn != nil {
// Ignore error because we don't care if connection is closed successfully or not.
_ = conn.Close()
}
}
}
return portforward.CreateTunnelToResourcePort(t, serverPod, remotePort, h.helmOptions.KubectlOptions, h.logger)
}

func (h *HelmCluster) SetupConsulClient(t *testing.T, secure bool) (client *api.Client, configAddress string) {
Expand Down
57 changes: 35 additions & 22 deletions acceptance/framework/k8s/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package k8s
import (
"context"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"regexp"
Expand All @@ -12,6 +14,8 @@ import (
terratestLogger "github.com/gruntwork-io/terratest/modules/logger"
"github.com/hashicorp/consul-k8s/acceptance/framework/environment"
"github.com/hashicorp/consul-k8s/acceptance/framework/logger"
"github.com/hashicorp/consul-k8s/acceptance/framework/portforward"
"github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
Expand Down Expand Up @@ -56,30 +60,39 @@ func WritePodsDebugInfoIfFailed(t *testing.T, kubectlOptions *k8s.KubectlOptions

// Describe pod and write it to a file.
writeResourceInfoToFile(t, pod.Name, "pod", testDebugDirectory, kubectlOptions)
}

// Get envoy configuration from the mesh gateways, if there are any.
meshGatewayPods, err := client.CoreV1().Pods(kubectlOptions.Namespace).List(context.Background(), metav1.ListOptions{LabelSelector: "component=mesh-gateway"})
require.NoError(t, err)

for _, mpod := range meshGatewayPods.Items {
// Get configdump from mesh gateway, passing the discard logger since we only need these logs written to the file (below).
configDump, err := RunKubectlAndGetOutputWithLoggerE(t, kubectlOptions, terratestLogger.Discard, "exec", mpod.Name, "-c", "consul-sidecar", "--", "curl", "-s", "localhost:19000/config_dump?format=json")
if err != nil {
configDump = fmt.Sprintf("Error getting config_dump: %s: %s", err, configDump)
// Check if the pod is connect-injected, and if so, dump envoy config information.
_, isServiceMeshPod := pod.Annotations[constants.KeyInjectStatus]
_, isGatewayPod := pod.Annotations[constants.AnnotationGatewayKind]
if isServiceMeshPod || isGatewayPod {
localPort := portforward.CreateTunnelToResourcePort(t, pod.Name, 19000, kubectlOptions, terratestLogger.Discard)

configDumpResp, err := http.DefaultClient.Get(fmt.Sprintf("http://%s/config_dump?format=json", localPort))
var configDump string
if err != nil {
configDump = fmt.Sprintf("Error getting config_dump: %s: %s", err, configDump)
} else {
configDumpRespBytes, err := io.ReadAll(configDumpResp.Body)
require.NoError(t, err)
configDump = string(configDumpRespBytes)
}

clustersResp, err := http.DefaultClient.Get(fmt.Sprintf("http://%s/clusters?format=json", localPort))
var clusters string
if err != nil {
clusters = fmt.Sprintf("Error getting clusters: %s: %s", err, clusters)
} else {
clustersRespBytes, err := io.ReadAll(clustersResp.Body)
require.NoError(t, err)
clusters = string(clustersRespBytes)
}

// Write config/clusters or err to file name <pod.Name>-envoy-[configdump/clusters].json
configDumpFilename := filepath.Join(testDebugDirectory, fmt.Sprintf("%s-envoy-configdump.json", pod.Name))
clustersFilename := filepath.Join(testDebugDirectory, fmt.Sprintf("%s-envoy-clusters.json", pod.Name))
require.NoError(t, os.WriteFile(configDumpFilename, []byte(configDump), 0600))
require.NoError(t, os.WriteFile(clustersFilename, []byte(clusters), 0600))
}
// Get cluster config from mesh gateway, passing the discard logger since we only need these logs written to the file (below).
clusters, err := RunKubectlAndGetOutputWithLoggerE(t, kubectlOptions, terratestLogger.Discard, "exec", mpod.Name, "-c", "consul-sidecar", "--", "curl", "-s", "localhost:19000/clusters?format=json")
if err != nil {
clusters = fmt.Sprintf("Error getting clusters: %s: %s", err, clusters)
}

// Write config/clusters or err to file name <pod.Name>-envoy-[configdump/clusters].json
configDumpFilename := filepath.Join(testDebugDirectory, fmt.Sprintf("%s-envoy-configdump.json", mpod.Name))
clustersFilename := filepath.Join(testDebugDirectory, fmt.Sprintf("%s-envoy-clusters.json", mpod.Name))
require.NoError(t, os.WriteFile(configDumpFilename, []byte(configDump), 0600))
require.NoError(t, os.WriteFile(clustersFilename, []byte(clusters), 0600))

}

// Describe any stateful sets.
Expand Down
79 changes: 79 additions & 0 deletions acceptance/framework/portforward/port_forward.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package portforward

import (
"fmt"
"net"
"testing"
"time"

terratestk8s "github.com/gruntwork-io/terratest/modules/k8s"
terratestLogger "github.com/gruntwork-io/terratest/modules/logger"
"github.com/hashicorp/consul-k8s/acceptance/framework/logger"
"github.com/hashicorp/consul/sdk/testutil/retry"
"github.com/stretchr/testify/require"
)

func CreateTunnelToResourcePort(t *testing.T, resourceName string, remotePort int, options *terratestk8s.KubectlOptions, logger terratestLogger.TestLogger) string {
localPort := terratestk8s.GetAvailablePort(t)
tunnel := terratestk8s.NewTunnelWithLogger(
options,
terratestk8s.ResourceTypePod,
resourceName,
localPort,
remotePort,
logger)

// Retry creating the port forward since it can fail occasionally.
retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 3}, t, func(r *retry.R) {
// NOTE: It's okay to pass in `t` to ForwardPortE despite being in a retry
// because we're using ForwardPortE (not ForwardPort) so the `t` won't
// get used to fail the test, just for logging.
require.NoError(r, tunnel.ForwardPortE(t))
})

doneChan := make(chan bool)

t.Cleanup(func() {
close(doneChan)
})

go monitorPortForwardedServer(t, localPort, tunnel, doneChan, resourceName, remotePort, options, logger)

return fmt.Sprintf("127.0.0.1:%d", localPort)
}

func monitorPortForwardedServer(t *testing.T, port int, tunnel *terratestk8s.Tunnel, doneChan chan bool, resourceName string, remotePort int, options *terratestk8s.KubectlOptions, log terratestLogger.TestLogger) {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()

for {
select {
case <-doneChan:
logger.Log(t, "stopping monitor of the port-forwarded server")
tunnel.Close()
return
case <-ticker.C:
conn, err := net.Dial("tcp", fmt.Sprintf("127.0.0.1:%d", port))
if err != nil {
logger.Log(t, "lost connection to port-forwarded server; restarting port-forwarding", "port", port)
tunnel.Close()
tunnel = terratestk8s.NewTunnelWithLogger(
options,
terratestk8s.ResourceTypePod,
resourceName,
port,
remotePort,
log)
err = tunnel.ForwardPortE(t)
if err != nil {
// If we couldn't establish a port forwarding channel, continue, so we can try again.
continue
}
}
if conn != nil {
// Ignore error because we don't care if connection is closed successfully or not.
_ = conn.Close()
}
}
}
}
48 changes: 24 additions & 24 deletions acceptance/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,30 @@ go 1.19

require (
github.com/gruntwork-io/terratest v0.31.2
github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211207212234-aea9efea5638
github.com/hashicorp/consul-k8s/control-plane v0.0.0-20221114215802-d1c85047c150
github.com/hashicorp/consul/api v1.14.0
github.com/hashicorp/consul/sdk v0.11.0
github.com/hashicorp/go-uuid v1.0.3
github.com/hashicorp/go-version v1.2.0
github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/vault/api v1.2.0
github.com/stretchr/testify v1.7.0
github.com/stretchr/testify v1.7.2
gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.22.2
k8s.io/apimachinery v0.22.2
k8s.io/client-go v0.22.2
)

require (
cloud.google.com/go v0.54.0 // indirect
github.com/armon/go-metrics v0.3.10 // indirect
cloud.google.com/go v0.81.0 // indirect
github.com/armon/go-metrics v0.4.1 // indirect
github.com/armon/go-radix v1.0.0 // indirect
github.com/aws/aws-sdk-go v1.30.27 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/cenkalti/backoff/v3 v3.0.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/evanphx/json-patch v4.11.0+incompatible // indirect
github.com/fatih/color v1.12.0 // indirect
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 // indirect
github.com/go-logr/logr v0.4.0 // indirect
Expand All @@ -42,7 +42,7 @@ require (
github.com/gruntwork-io/gruntwork-cli v0.7.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-hclog v0.16.2 // indirect
github.com/hashicorp/go-hclog v1.2.2 // indirect
github.com/hashicorp/go-immutable-radix v1.3.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-plugin v1.0.1 // indirect
Expand All @@ -53,22 +53,22 @@ require (
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/serf v0.9.7 // indirect
github.com/hashicorp/serf v0.10.1 // indirect
github.com/hashicorp/vault/sdk v0.2.1 // indirect
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jmespath/go-jmespath v0.3.0 // indirect
github.com/json-iterator/go v1.1.11 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.13 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mitchellh/copystructure v1.0.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.0 // indirect
github.com/mitchellh/mapstructure v1.4.2 // indirect
github.com/mitchellh/reflectwalk v1.0.0 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/oklog/run v1.0.0 // indirect
github.com/onsi/ginkgo v1.16.4 // indirect
github.com/onsi/gomega v1.15.0 // indirect
Expand All @@ -82,23 +82,23 @@ require (
github.com/spf13/pflag v1.0.5 // indirect
github.com/urfave/cli v1.22.2 // indirect
go.uber.org/atomic v1.7.0 // indirect
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect
golang.org/x/text v0.3.6 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect
google.golang.org/grpc v1.38.0 // indirect
google.golang.org/protobuf v1.26.0 // indirect
google.golang.org/grpc v1.48.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/klog/v2 v2.9.0 // indirect
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect
k8s.io/utils v0.0.0-20220812165043-ad590609e2e5 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect
sigs.k8s.io/yaml v1.2.0 // indirect
)
Loading