diff --git a/pkg/trigger/discovery_handler.go b/pkg/trigger/discovery_handler.go index e7549c773..798df93a9 100644 --- a/pkg/trigger/discovery_handler.go +++ b/pkg/trigger/discovery_handler.go @@ -26,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/discovery" "k8s.io/klog" migrationv1alpha1 "sigs.k8s.io/kube-storage-version-migrator/pkg/apis/migration/v1alpha1" @@ -44,8 +45,13 @@ func (mt *MigrationTrigger) processDiscovery(ctx context.Context) { return true, nil }) if err != nil { - utilruntime.HandleError(fmt.Errorf("Abort processing discovery document: %v", err)) - return + if discovery.IsGroupDiscoveryFailedError(err2) { + // process the partial discovery result, and update the heartbeat for + // resources that do have a valid discovery document + klog.Warningf("failed to discover some groups: %v; processing partial result", err2.(*discovery.ErrGroupDiscoveryFailed).Groups) + } else { + klog.Warningf("failed to discover preferred resources: %v", err2) + } } mt.heartbeat = metav1.Now() for _, l := range resources { diff --git a/pkg/trigger/discovery_handler_test.go b/pkg/trigger/discovery_handler_test.go index b74a53f98..0aad39632 100644 --- a/pkg/trigger/discovery_handler_test.go +++ b/pkg/trigger/discovery_handler_test.go @@ -28,6 +28,8 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" core "k8s.io/client-go/testing" "k8s.io/client-go/tools/cache" @@ -372,3 +374,59 @@ func verifyStorageStateUpdate(t *testing.T, a core.Action, expectedHeartbeat met t.Fatalf("expected hashes %v, got %v", e, a) } } + +// FakeClientset wraps the generated fake Clientset and overrides the Discovery interface +type FakeClientset struct { + *fake.Clientset +} + +func (f *FakeClientset) Discovery() discovery.DiscoveryInterface { + return &FakeDiscovery{FakeDiscovery: f.Clientset.Discovery().(*fakediscovery.FakeDiscovery)} +} + +// FakeDiscovery wraps the client-go FakeDiscovery and overrides the ServerPreferredResources method +type FakeDiscovery struct { + *fakediscovery.FakeDiscovery +} + +func (f *FakeDiscovery) ServerPreferredResources() ([]*metav1.APIResourceList, error) { + failedGroups := make(map[schema.GroupVersion]error) + gv := schema.GroupVersion{Group: "test.k8s.io", Version: "v1"} + failedGroups[gv] = fmt.Errorf("test partial discovery failure") + return []*metav1.APIResourceList{ + { + APIResources: []metav1.APIResource{newAPIResource()}, + }, + }, &discovery.ErrGroupDiscoveryFailed{Groups: failedGroups} + +} + +func TestProcessDiscoveryPartialFailure(t *testing.T) { + client := fake.NewSimpleClientset(newMigrationList()) + // overrides the ServerPreferredResources method of the simple clientset + trigger := NewMigrationTrigger(&FakeClientset{Clientset: client}) + stopCh := make(chan struct{}) + defer close(stopCh) + go trigger.migrationInformer.Run(stopCh) + if !cache.WaitForCacheSync(stopCh, trigger.migrationInformer.HasSynced) { + utilruntime.HandleError(fmt.Errorf("Unable to sync caches")) + return + } + trigger.heartbeat = metav1.Now() + // let trigger controller invokes ServerPreferredResources method to discover + // the API resources + trigger.processDiscovery(context.TODO()) + actions := client.Actions() + verifyCleanupAndLaunch(t, actions[3:7]) + + c, ok := actions[8].(core.CreateAction) + if !ok { + t.Fatalf("expected create action") + } + r := schema.GroupVersionResource{Group: "migration.k8s.io", Version: "v1alpha1", Resource: "storagestates"} + if c.GetResource() != r { + t.Fatalf("unexpected resource %v", c.GetResource()) + } + + verifyStorageStateUpdate(t, actions[9], trigger.heartbeat, newAPIResource().StorageVersionHash, []string{v1alpha1.Unknown}) +}