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

Backport of Add fixes for flaky-cni and failing cloud-nightly tests into release/1.3.x #3777

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions acceptance/framework/consul/helm_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ func NewHelmCluster(
func (h *HelmCluster) Create(t *testing.T) {
t.Helper()

// check and remove any CRDs with finalizers
helpers.GetCRDRemoveFinalizers(t, h.helmOptions.KubectlOptions)

// Make sure we delete the cluster if we receive an interrupt signal and
// register cleanup so that we delete the cluster when test finishes.
helpers.Cleanup(t, h.noCleanupOnFailure, h.noCleanup, func() {
Expand Down
96 changes: 66 additions & 30 deletions acceptance/framework/helpers/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"time"

"github.com/gruntwork-io/terratest/modules/helm"
"github.com/gruntwork-io/terratest/modules/k8s"
terratestLogger "github.com/gruntwork-io/terratest/modules/logger"
"github.com/gruntwork-io/terratest/modules/random"
"github.com/hashicorp/consul-k8s/acceptance/framework/logger"
Expand Down Expand Up @@ -197,42 +198,52 @@ type Command struct {
Logger *terratestLogger.Logger
}

func RunCommand(t testutil.TestingTB, command Command) (string, error) {
type cmdResult struct {
output string
err error
}

func RunCommand(t testutil.TestingTB, options *k8s.KubectlOptions, command Command) (string, error) {
t.Helper()
cmd, err := exec.Command(command.Command, command.Args...).CombinedOutput()

// Check and remove finalizers in crds in the namespace
resultCh := make(chan *cmdResult, 1)

go func() {
output, err := exec.Command(command.Command, command.Args...).CombinedOutput()
resultCh <- &cmdResult{output: string(output), err: err}
}()

// might not be needed
for _, arg := range command.Args {
if strings.Contains(arg, "delete") {
errCh := make(chan error)
go func() {
errCh <- getCRDRemoveFinalizers(t)
GetCRDRemoveFinalizers(t, options)
}()
if err := <-errCh; err != nil {
return "", err
}
}
}

return string(cmd), err
select {
case res := <-resultCh:
return res.output, res.err
// Sometimes this func runs for too long handle timeout if needed.
case <-time.After(30 * time.Second):
GetCRDRemoveFinalizers(t, options)
logger.Logf(t, "RunCommand timed out")
return "", nil
}
}

// getCRDRemoveFinalizers gets CRDs with finalizers and removes them.
func getCRDRemoveFinalizers(t testutil.TestingTB) error {
func GetCRDRemoveFinalizers(t testutil.TestingTB, options *k8s.KubectlOptions) {
t.Helper()
// Get CRD names with finalizers
crdNames, err := getCRDsWithFinalizers()
crdNames, err := getCRDsWithFinalizers(options)
if err != nil {
return err
logger.Logf(t, "Unable to get CRDs with finalizers, %v.", err)
}

// Remove finalizers for each CRD with finalizers
if len(crdNames) > 0 {
if err := removeFinalizers(crdNames); err != nil {
return err
}
removeFinalizers(t, options, crdNames)
}
return nil
}

// CRD struct to parse CRD JSON output.
Expand All @@ -245,15 +256,19 @@ type CRD struct {
} `json:"items"`
}

// getCRDsWithFinalizers gets CRDs with finalizers.
func getCRDsWithFinalizers() ([]string, error) {
cmd := exec.Command("kubectl", "get", "crd", "-o=json")
func getCRDsWithFinalizers(options *k8s.KubectlOptions) ([]string, error) {
cmdArgs := createCmdArgs(options)
args := []string{"get", "crd", "-o=json"}

output, err := cmd.CombinedOutput()
if err != nil {
return nil, fmt.Errorf("error executing command: %v", err)
cmdArgs = append(cmdArgs, args...)
command := Command{
Command: "kubectl",
Args: cmdArgs,
Env: options.Env,
}

output, err := exec.Command(command.Command, command.Args...).CombinedOutput()

var crds CRD
if err := json.Unmarshal(output, &crds); err != nil {
return nil, fmt.Errorf("error parsing JSON: %v", err)
Expand All @@ -266,19 +281,40 @@ func getCRDsWithFinalizers() ([]string, error) {
}
}

return crdNames, nil
return crdNames, err
}

// removeFinalizers removes finalizers from CRDs.
func removeFinalizers(crdNames []string) error {
func removeFinalizers(t testutil.TestingTB, options *k8s.KubectlOptions, crdNames []string) {
cmdArgs := createCmdArgs(options)
for _, crd := range crdNames {
cmd := exec.Command("kubectl", "patch", "crd", crd, "--type=json", "-p=[{\"op\": \"remove\", \"path\": \"/metadata/finalizers\"}]")
args := []string{"patch", "crd", crd, "--type=json", "-p=[{\"op\": \"remove\", \"path\": \"/metadata/finalizers\"}]"}

err := cmd.Run()
cmdArgs = append(cmdArgs, args...)
command := Command{
Command: "kubectl",
Args: cmdArgs,
Env: options.Env,
}

_, err := exec.Command(command.Command, command.Args...).CombinedOutput()
if err != nil {
return fmt.Errorf("error removing finalizers from CRD %s: %v", crd, err)
logger.Logf(t, "Unable to remove finalizers, proceeding anyway: %v.", err)
}
fmt.Printf("Finalizers removed from CRD %s\n", crd)
}
return nil
}

func createCmdArgs(options *k8s.KubectlOptions) []string {
var cmdArgs []string
if options.ContextName != "" {
cmdArgs = append(cmdArgs, "--context", options.ContextName)
}
if options.ConfigPath != "" {
cmdArgs = append(cmdArgs, "--kubeconfig", options.ConfigPath)
}
if options.Namespace != "" {
cmdArgs = append(cmdArgs, "--namespace", options.Namespace)
}
return cmdArgs
}
5 changes: 1 addition & 4 deletions acceptance/framework/k8s/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,7 @@ func CheckStaticServerConnectionMultipleFailureMessages(t *testing.T, options *k
expectedOutput = expectedSuccessOutput
}

retrier := &retry.Counter{
Count: 10,
Wait: 2 * time.Second,
}
retrier := &retry.Counter{Count: 30, Wait: 2 * time.Second}

args := []string{"exec", resourceType + sourceApp, "-c", sourceApp, "--", "curl", "-vvvsSf"}
args = append(args, curlArgs...)
Expand Down
2 changes: 1 addition & 1 deletion acceptance/framework/k8s/kubectl.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func RunKubectlAndGetOutputWithLoggerE(t *testing.T, options *k8s.KubectlOptions
var output string
var err error
retry.RunWith(counter, t, func(r *retry.R) {
output, err = helpers.RunCommand(r, command)
output, err = helpers.RunCommand(r, options, command)
if err != nil {
// Want to retry on errors connecting to actual Kube API because
// these are intermittent.
Expand Down
25 changes: 11 additions & 14 deletions acceptance/framework/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,19 @@ package logger

import (
"fmt"
"testing"
"github.com/hashicorp/consul/sdk/testutil"
"time"

terratestTesting "github.com/gruntwork-io/terratest/modules/testing"
terratesting "github.com/gruntwork-io/terratest/modules/testing"
)

// TestLogger implements terratest's TestLogger interface
// so that we can pass it to terratest objects to have consistent logging
// across all tests.
// TestLogger implements Terratest's TestLogger interface so that we can pass it to Terratest objects to have consistent
// logging across all tests.
type TestLogger struct{}

// Logf takes a format string and args and calls Logf function.
func (tl TestLogger) Logf(t terratestTesting.TestingT, format string, args ...interface{}) {
tt, ok := t.(*testing.T)
func (tl TestLogger) Logf(t terratesting.TestingT, format string, args ...any) {
tt, ok := t.(testutil.TestingTB)
if !ok {
t.Error("failed to cast")
}
Expand All @@ -27,20 +26,18 @@ func (tl TestLogger) Logf(t terratestTesting.TestingT, format string, args ...in
Logf(tt, format, args...)
}

// Logf takes a format string and args and logs
// formatted string with a timestamp.
func Logf(t *testing.T, format string, args ...interface{}) {
// Logf takes a format string and args and logs formatted string with a timestamp.
func Logf(t testutil.TestingTB, format string, args ...any) {
t.Helper()

log := fmt.Sprintf(format, args...)
Log(t, log)
}

// Log calls t.Log, adding an RFC3339 timestamp to the beginning of the log line.
func Log(t *testing.T, args ...interface{}) {
// Log calls t.Log or r.Log, adding an RFC3339 timestamp to the beginning of the log line.
func Log(t testutil.TestingTB, args ...any) {
t.Helper()

allArgs := []interface{}{time.Now().Format(time.RFC3339)}
allArgs := []any{time.Now().Format(time.RFC3339)}
allArgs = append(allArgs, args...)
t.Log(allArgs...)
}
Loading