Skip to content
Open
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
26 changes: 14 additions & 12 deletions pkg/bugreport/bugreport.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const (
// bug report
type BugReporter struct {
client client.Reader
clientSet *kubernetes.Clientset
clientSet kubernetes.Interface
cm *unstructured.Unstructured
enabled map[Product]bool
util.ConfigManagementClient
Expand All @@ -79,7 +79,7 @@ type BugReporter struct {
}

// New creates a new BugReport
func New(ctx context.Context, c client.Client, cs *kubernetes.Clientset) (*BugReporter, error) {
func New(ctx context.Context, c client.Client, cs kubernetes.Interface) (*BugReporter, error) {
cm := &unstructured.Unstructured{}
cm.SetGroupVersionKind(schema.GroupVersionKind{
Group: configmanagement.GroupName,
Expand All @@ -94,22 +94,24 @@ func New(ctx context.Context, c client.Client, cs *kubernetes.Clientset) (*BugRe
errorList = append(errorList, err)
}

if err := c.Get(ctx, types.NamespacedName{Name: util.ConfigManagementName}, cm); err != nil {
err = c.Get(ctx, types.NamespacedName{Name: util.ConfigManagementName}, cm)

if err != nil {
if meta.IsNoMatchError(err) {
fmt.Println("kind <<" + configmanagement.OperatorKind + ">> is not registered with the cluster")
} else if errors.IsNotFound(err) {
fmt.Println("ConfigManagement object not found")
} else {
errorList = append(errorList, err)
}
}

isMulti, _, err := unstructured.NestedBool(cm.UnstructuredContent(), "spec", "enableMultiRepo")
if err != nil {
fmt.Println("ConfigManagement parsing error", err)
}
if !isMulti {
util.MonoRepoNotice(os.Stdout, currentk8sContext)
} else {
isMulti, found, err := unstructured.NestedBool(cm.UnstructuredContent(), "spec", "enableMultiRepo")
if err != nil {
fmt.Println("ConfigManagement parsing error", err)
}
if found && !isMulti {
util.MonoRepoNotice(os.Stdout, currentk8sContext)
}
}

return &BugReporter{
Expand Down Expand Up @@ -282,7 +284,7 @@ type resourcesToReadables func(*unstructured.UnstructuredList, string) []Readabl
// fetchResources provides a set of Readables for resources with a given group and version
// toReadables: the function that converts the resources to readables.
func (b *BugReporter) fetchResources(ctx context.Context, gv schema.GroupVersion, toReadables resourcesToReadables) (rd []Readable) {
rl, err := b.clientSet.ServerResourcesForGroupVersion(gv.String())
rl, err := b.clientSet.Discovery().ServerResourcesForGroupVersion(gv.String())
if err != nil {
if errors.IsNotFound(err) {
fmt.Printf("No %s resources found on cluster\n", gv.Group)
Expand Down
184 changes: 184 additions & 0 deletions pkg/bugreport/bugreport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,201 @@
package bugreport

import (
"bytes"
"context"
"errors"
"fmt"
"io"
"os"
"sort"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
k8sfake "k8s.io/client-go/kubernetes/fake"
"kpt.dev/configsync/cmd/nomos/util"
"kpt.dev/configsync/pkg/api/configmanagement"
"kpt.dev/configsync/pkg/client/restconfig"
"kpt.dev/configsync/pkg/core"
"kpt.dev/configsync/pkg/core/k8sobjects"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/client/interceptor"
)

func configManagementObject(multiRepo bool) *unstructured.Unstructured {
u := &unstructured.Unstructured{}
u.SetGroupVersionKind(schema.GroupVersionKind{
Group: configmanagement.GroupName,
Version: "v1",
Kind: configmanagement.OperatorKind,
})
u.SetName(util.ConfigManagementName)
_ = unstructured.SetNestedField(u.Object, multiRepo, "spec", "enableMultiRepo")

return u
}

func captureOutput(t *testing.T, f func()) string {
old := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w

f()
assert.NoError(t, w.Close())

var buf bytes.Buffer
_, _ = io.Copy(&buf, r)
os.Stdout = old
return buf.String()
}

func TestNew(t *testing.T) {
cmMultiRepo := configManagementObject(true)
cmMonoRepo := configManagementObject(false)

testCases := []struct {
name string
client client.Client
clientset *k8sfake.Clientset
expectedErrCount int
contextErr error
expectedOutput string
checkFn func(t *testing.T, br *BugReporter)
}{
{
name: "no configmanagement object",
client: fake.NewClientBuilder().WithScheme(core.Scheme).WithObjects().Build(),
clientset: k8sfake.NewSimpleClientset(),
expectedErrCount: 0,
expectedOutput: "ConfigManagement object not found\n",
checkFn: func(t *testing.T, br *BugReporter) {
if br.cm.GetName() != "" {
t.Errorf("expected empty cm object, got %v", br.cm)
}
},
},
{
name: "multi-repo",
client: fake.NewClientBuilder().WithObjects(cmMultiRepo).Build(),
clientset: k8sfake.NewSimpleClientset(),
expectedErrCount: 0,
expectedOutput: "",
checkFn: func(t *testing.T, br *BugReporter) {
if br.cm.GetName() != util.ConfigManagementName {
t.Errorf("expected cm object, got empty")
}
enabled := br.EnabledServices()
if !enabled[ConfigSync] {
t.Error("ConfigSync should be enabled for multi-repo")
}
if !enabled[ResourceGroup] {
t.Error("ResourceGroup should be enabled for multi-repo")
}
},
},
{
name: "mono-repo",
client: fake.NewClientBuilder().WithObjects(cmMonoRepo).Build(),
clientset: k8sfake.NewSimpleClientset(),
expectedErrCount: 0,
expectedOutput: "\x1b[33mNotice: The cluster \"context\" is still running in the legacy mode.\n" +
"Run `nomos migrate` to enable multi-repo mode. " +
"It provides you with additional features and gives you the flexibility to sync to a single repository, " +
"or multiple repositories.\x1b[0m\n",
checkFn: func(t *testing.T, br *BugReporter) {
if br.cm.GetName() != util.ConfigManagementName {
t.Errorf("expected cm object, got empty")
}
},
},
{
name: "kubeconfig error",

client: fake.NewClientBuilder().Build(),
clientset: k8sfake.NewSimpleClientset(),
expectedErrCount: 1,
expectedOutput: "ConfigManagement object not found\n",
contextErr: errors.New("context error"),
checkFn: func(t *testing.T, br *BugReporter) {
if br.k8sContext != "" {
t.Errorf("expected empty k8sContext, got %q", br.k8sContext)
}
if len(br.ErrorList) != 1 {
t.Fatalf("expected 1 error, got %d", len(br.ErrorList))
}
},
},
{
name: "no kind match error",
client: fake.NewClientBuilder().WithScheme(core.Scheme).WithInterceptorFuncs(
interceptor.Funcs{
Get: func(_ context.Context, _ client.WithWatch, _ client.ObjectKey, _ client.Object, _ ...client.GetOption) error {
return &meta.NoKindMatchError{
GroupKind: schema.GroupKind{
Group: configmanagement.GroupName,
Kind: configmanagement.OperatorKind,
},
SearchedVersions: []string{"v1"},
}
},
}).Build(),
clientset: k8sfake.NewSimpleClientset(),
expectedErrCount: 0,
expectedOutput: "kind <<ConfigManagement>> is not registered with the cluster\n",
},
{
name: "generic get error",
client: fake.NewClientBuilder().WithScheme(core.Scheme).WithInterceptorFuncs(
interceptor.Funcs{
Get: func(_ context.Context, _ client.WithWatch, _ client.ObjectKey, _ client.Object, _ ...client.GetOption) error {
return errors.New("generic get error")
},
}).Build(),
clientset: k8sfake.NewSimpleClientset(),
expectedErrCount: 1,
expectedOutput: "",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
restconfig.CurrentContextName = func() (string, error) {
if tc.contextErr != nil {
return "", tc.contextErr
}
return "context", nil
}

var br *BugReporter
var err error
output := captureOutput(t, func() {
br, err = New(context.Background(), tc.client, tc.clientset)
})

if err != nil {
t.Fatalf("New() returned an unexpected error: %v", err)
}

if len(br.ErrorList) != tc.expectedErrCount {
t.Errorf("got %d errors, want %d. Errors: %v", len(br.ErrorList), tc.expectedErrCount, br.ErrorList)
}

if diff := cmp.Diff(tc.expectedOutput, output); diff != "" {
t.Errorf("unexpected output (-want +got):\n%s", diff)
}

if tc.checkFn != nil {
tc.checkFn(t, br)
}
})
}
}

func TestAssembleLogSources(t *testing.T) {
tests := []struct {
name string
Expand Down
3 changes: 3 additions & 0 deletions vendor/modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1584,6 +1584,8 @@ sigs.k8s.io/controller-runtime/pkg/certwatcher/metrics
sigs.k8s.io/controller-runtime/pkg/client
sigs.k8s.io/controller-runtime/pkg/client/apiutil
sigs.k8s.io/controller-runtime/pkg/client/config
sigs.k8s.io/controller-runtime/pkg/client/fake
sigs.k8s.io/controller-runtime/pkg/client/interceptor
sigs.k8s.io/controller-runtime/pkg/cluster
sigs.k8s.io/controller-runtime/pkg/config
sigs.k8s.io/controller-runtime/pkg/controller
Expand All @@ -1601,6 +1603,7 @@ sigs.k8s.io/controller-runtime/pkg/internal/flock
sigs.k8s.io/controller-runtime/pkg/internal/httpserver
sigs.k8s.io/controller-runtime/pkg/internal/log
sigs.k8s.io/controller-runtime/pkg/internal/metrics
sigs.k8s.io/controller-runtime/pkg/internal/objectutil
sigs.k8s.io/controller-runtime/pkg/internal/recorder
sigs.k8s.io/controller-runtime/pkg/internal/source
sigs.k8s.io/controller-runtime/pkg/internal/syncs
Expand Down
Loading