Skip to content

Commit

Permalink
feat(e2e): add local host support bundle test (#1680)
Browse files Browse the repository at this point in the history
  • Loading branch information
DexterYan authored Nov 8, 2024
1 parent d25aa7d commit 40eef3c
Show file tree
Hide file tree
Showing 6 changed files with 378 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/build-test-deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,12 @@ jobs:
name: support-bundle
path: bin/
- run: chmod +x bin/support-bundle
- name: Download preflight binary
uses: actions/download-artifact@v4
with:
name: preflight
path: bin/
- run: chmod +x bin/preflight
- run: make support-bundle-e2e-go-test

compile-collect:
Expand Down
96 changes: 96 additions & 0 deletions test/e2e/preflight/host_local_collector_e2e_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package e2e

import (
"bytes"
"context"
"fmt"
"os"
"os/exec"
"slices"
"strings"
"testing"

"sigs.k8s.io/e2e-framework/pkg/envconf"
"sigs.k8s.io/e2e-framework/pkg/features"
)

func TestHostLocalCollector(t *testing.T) {
tests := []struct {
paths []string
notExpectedPaths []string
expectType string
}{
{
paths: []string{
"cpu.json",
},
notExpectedPaths: []string{
"node_list.json",
},
expectType: "file",
},
}

feature := features.New("Preflight Host Local Collector").
Assess("check preflight catch host local collector", func(ctx context.Context, t *testing.T, c *envconf.Config) context.Context {
var out bytes.Buffer
var errOut bytes.Buffer
preflightName := "preflightbundle"
cmd := exec.CommandContext(ctx, preflightBinary(), "spec/localHostCollectors.yaml", "--interactive=false")
cmd.Stdout = &out
cmd.Stderr = &errOut

err := cmd.Run()
tarPath := GetFilename(errOut.String(), preflightName)
if err != nil {
if tarPath == "" {
t.Error(err)
}
}

defer func() {
err := os.Remove(tarPath)
if err != nil {
t.Error("Error remove file:", err)
}
}()

targetFile := fmt.Sprintf("%s/host-collectors/system/", strings.TrimSuffix(tarPath, ".tar.gz"))

files, _, err := readFilesAndFoldersFromTar(tarPath, targetFile)
if err != nil {
t.Error(err)
}

for _, test := range tests {
if test.expectType == "file" {
for _, path := range test.paths {
if !slices.Contains(files, path) {
t.Errorf("Expected file %s not found in the tarball", path)
}
}
for _, path := range test.notExpectedPaths {
if slices.Contains(files, path) {
t.Errorf("Unexpected file %s found in the tarball", path)
}
}
}
}
return ctx
}).Feature()
testenv.Test(t, feature)
}

func GetFilename(input, prefix string) string {
// Split the input into words
words := strings.Fields(input)
// Iterate over each word to find the one starting with the prefix
for _, word := range words {
if strings.HasPrefix(word, prefix) {
return word
}
}

// Return an empty string if no match is found
return ""
}
146 changes: 146 additions & 0 deletions test/e2e/preflight/main_e2e_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package e2e

import (
"archive/tar"
"bytes"
"compress/gzip"
"context"
"flag"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"testing"

"k8s.io/klog/v2"
"sigs.k8s.io/e2e-framework/pkg/env"
"sigs.k8s.io/e2e-framework/pkg/envconf"
"sigs.k8s.io/e2e-framework/pkg/envfuncs"
"sigs.k8s.io/e2e-framework/support/kind"
)

var testenv env.Environment

const ClusterName = "kind-cluster"

func TestMain(m *testing.M) {
// enable klog
klog.InitFlags(nil)
if os.Getenv("E2E_VERBOSE") == "1" {
_ = flag.Set("v", "10")
}

testenv = env.New()
namespace := envconf.RandomName("default", 16)
testenv.Setup(
envfuncs.CreateCluster(kind.NewProvider(), ClusterName),
envfuncs.CreateNamespace(namespace),
)
testenv.Finish(
envfuncs.DeleteNamespace(namespace),
envfuncs.DestroyCluster(ClusterName),
)
os.Exit(testenv.Run(m))
}

func getClusterFromContext(t *testing.T, ctx context.Context, clusterName string) *kind.Cluster {
provider, ok := envfuncs.GetClusterFromContext(ctx, clusterName)
if !ok {
t.Fatalf("Failed to extract kind cluster %s from context", clusterName)
}
cluster, ok := provider.(*kind.Cluster)
if !ok {
t.Fatalf("Failed to cast kind cluster %s from provider", clusterName)
}

return cluster
}

func readFilesAndFoldersFromTar(tarPath, targetFolder string) ([]string, []string, error) {
file, err := os.Open(tarPath)
if err != nil {
return nil, nil, fmt.Errorf("Error opening file: %w", err)
}
defer file.Close()

gzipReader, err := gzip.NewReader(file)
if err != nil {
return nil, nil, fmt.Errorf("Error initializing gzip reader: %w", err)
}
defer gzipReader.Close()

tarReader := tar.NewReader(gzipReader)
var files []string
var folders []string

for {
header, err := tarReader.Next()

if err == io.EOF {
break
}
if err != nil {
return nil, nil, fmt.Errorf("Error reading tar: %w", err)
}

if strings.HasPrefix(header.Name, targetFolder) {
relativePath, err := filepath.Rel(targetFolder, header.Name)
if err != nil {
return nil, nil, fmt.Errorf("Error getting relative path: %w", err)
}
if relativePath != "" {
relativeDir := filepath.Dir(relativePath)
if relativeDir != "." {
parentDir := strings.Split(relativeDir, "/")[0]
folders = append(folders, parentDir)
} else {
files = append(files, relativePath)
}
}
}
}

return files, folders, nil
}

func readFileFromTar(tarPath, targetFile string) ([]byte, error) {
file, err := os.Open(tarPath)
if err != nil {
return nil, fmt.Errorf("Error opening file: %w", err)
}
defer file.Close()

gzipReader, err := gzip.NewReader(file)
if err != nil {
return nil, fmt.Errorf("Error initializing gzip reader: %w", err)
}
defer gzipReader.Close()

tarReader := tar.NewReader(gzipReader)

for {
header, err := tarReader.Next()

if err == io.EOF {
break
}
if err != nil {
return nil, fmt.Errorf("Error reading tar: %w", err)
}

if header.Name == targetFile {
buf := new(bytes.Buffer)
_, err = io.Copy(buf, tarReader)
if err != nil {
return nil, fmt.Errorf("Error copying data: %w", err)
}
return buf.Bytes(), nil
}
}
return nil, fmt.Errorf("File not found: %q", targetFile)
}

func preflightBinary() string {
return "../../../bin/preflight"
}
19 changes: 19 additions & 0 deletions test/e2e/preflight/spec/localHostCollectors.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: troubleshoot.sh/v1beta2
kind: HostPreflight
metadata:
name: ec-cluster-preflight
spec:
collectors:
- cpu: {}
analyzers:
- cpu:
checkName: "Number of CPUs"
outcomes:
- pass:
when: "count < 2"
message: At least 2 CPU cores are required, and 4 CPU cores are recommended
- warn:
when: "count < 4"
message: At least 4 CPU cores are recommended
- pass:
message: This server has at least 4 CPU cores
78 changes: 78 additions & 0 deletions test/e2e/support-bundle/host_local_collector_e2e_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package e2e

import (
"bytes"
"context"
"fmt"
"os"
"os/exec"
"testing"

"golang.org/x/exp/slices"
"sigs.k8s.io/e2e-framework/pkg/envconf"
"sigs.k8s.io/e2e-framework/pkg/features"
)

func TestHostLocalCollector(t *testing.T) {
tests := []struct {
paths []string
notExpectedPaths []string
expectType string
}{
{
paths: []string{
"cpu.json",
"hostos_info.json",
"ipv4Interfaces.json",
"memory.json",
},
notExpectedPaths: []string{
"node_list.json",
},
expectType: "file",
},
}
feature := features.New("Host Local Collector").
Assess("check support bundle catch host local collector", func(ctx context.Context, t *testing.T, c *envconf.Config) context.Context {
var out bytes.Buffer
supportbundleName := "host-local-collector"
tarPath := fmt.Sprintf("%s.tar.gz", supportbundleName)
targetFile := fmt.Sprintf("%s/host-collectors/system/", supportbundleName)
cmd := exec.CommandContext(ctx, sbBinary(), "spec/localHostCollectors.yaml", "--interactive=false", fmt.Sprintf("-o=%s", supportbundleName))
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
t.Error(err)
}

defer func() {
err := os.Remove(fmt.Sprintf("%s.tar.gz", supportbundleName))
if err != nil {
t.Error("Error remove file:", err)
}
}()

files, _, err := readFilesAndFoldersFromTar(tarPath, targetFile)
if err != nil {
t.Error(err)
}

for _, test := range tests {
if test.expectType == "file" {
for _, path := range test.notExpectedPaths {
if slices.Contains(files, path) {
t.Fatalf("Unexpected file %s found", path)
}
}
for _, path := range test.paths {
if !slices.Contains(files, path) {
t.Fatalf("Expected file %s not found", path)
}
}
}
}

return ctx
}).Feature()
testenv.Test(t, feature)
}
33 changes: 33 additions & 0 deletions test/e2e/support-bundle/spec/localHostCollectors.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
apiVersion: troubleshoot.sh/v1beta2
kind: SupportBundle
metadata:
name: "remote-host-collectors"
spec:
hostCollectors:
- ipv4Interfaces: {}
- hostServices: {}
- cpu: {}
- hostOS: {}
- memory: {}
- blockDevices: {}
- kernelConfigs: {}
- copy:
collectorName: etc-resolv
path: /etc/resolv.conf
- dns:
collectorName: replicated-app-resolve
hostnames:
- replicated.app
- diskUsage:
collectorName: root-disk-usage
path: /
- diskUsage:
collectorName: tmp
path: /tmp
- http:
collectorName: get-replicated-app
get:
url: https://replicated.app
- run:
collectorName: uptime
command: uptime

0 comments on commit 40eef3c

Please sign in to comment.