diff --git a/go.mod b/go.mod index 1bf645791..32d8a94c0 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/onsi/ginkgo v1.11.0 github.com/onsi/gomega v1.8.1 - github.com/open-cluster-management/api v0.0.0-20200512175145-bed9ce79e17e + github.com/open-cluster-management/api v0.0.0-20200528225735-c85cec6fa5b0 github.com/openshift/build-machinery-go v0.0.0-20200211121458-5e3d6e570160 github.com/openshift/library-go v0.0.0-20200414135834-ccc4bb27d032 github.com/spf13/cobra v1.0.0 @@ -18,5 +18,6 @@ require ( k8s.io/component-base v0.18.2 k8s.io/klog v1.0.0 k8s.io/kubectl v0.18.2 + k8s.io/utils v0.0.0-20200327001022-6496210b90e8 sigs.k8s.io/controller-runtime v0.6.0 ) diff --git a/go.sum b/go.sum index 04f14fd79..23f0bc5b5 100644 --- a/go.sum +++ b/go.sum @@ -303,8 +303,8 @@ github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34= github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/open-cluster-management/api v0.0.0-20200512175145-bed9ce79e17e h1:WIzt0Bs7g0PIrVAVSobXAbDqvC2P5VjEwFTpjB4777I= -github.com/open-cluster-management/api v0.0.0-20200512175145-bed9ce79e17e/go.mod h1:RgKeB8PJ7upe2QXy/MpCejU/xm2G6/i0Y+/itWuPugs= +github.com/open-cluster-management/api v0.0.0-20200528225735-c85cec6fa5b0 h1:NurWtcX3/i6vBL022aM+VboyWx8FpNBj7SoO/uT+k0o= +github.com/open-cluster-management/api v0.0.0-20200528225735-c85cec6fa5b0/go.mod h1:RgKeB8PJ7upe2QXy/MpCejU/xm2G6/i0Y+/itWuPugs= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.0.0-20191031171055-b133feaeeb2e/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= diff --git a/pkg/spoke/controllers/deletioncontroller/deletion_controller.go b/pkg/spoke/controllers/deletioncontroller/deletion_controller.go new file mode 100644 index 000000000..8b82ce067 --- /dev/null +++ b/pkg/spoke/controllers/deletioncontroller/deletion_controller.go @@ -0,0 +1,168 @@ +package deletioncontroller + +import ( + "context" + "fmt" + "reflect" + "sort" + + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/client-go/dynamic" + "k8s.io/klog" + + workv1client "github.com/open-cluster-management/api/client/work/clientset/versioned/typed/work/v1" + workinformer "github.com/open-cluster-management/api/client/work/informers/externalversions/work/v1" + worklister "github.com/open-cluster-management/api/client/work/listers/work/v1" + workapiv1 "github.com/open-cluster-management/api/work/v1" + "github.com/openshift/library-go/pkg/controller/factory" + "github.com/openshift/library-go/pkg/operator/events" +) + +// StaleManifestDeletionController is to reconcile the applied resources of manifest work and +// delete any resouce which is no longer maintained by the manifest work +type StaleManifestDeletionController struct { + manifestWorkClient workv1client.ManifestWorkInterface + manifestWorkLister worklister.ManifestWorkNamespaceLister + spokeDynamicClient dynamic.Interface +} + +// NewStaleManifestDeletionController returns a StaleManifestDeletionController +func NewStaleManifestDeletionController( + recorder events.Recorder, + spokeDynamicClient dynamic.Interface, + manifestWorkClient workv1client.ManifestWorkInterface, + manifestWorkInformer workinformer.ManifestWorkInformer, + manifestWorkLister worklister.ManifestWorkNamespaceLister) factory.Controller { + + controller := &StaleManifestDeletionController{ + manifestWorkClient: manifestWorkClient, + manifestWorkLister: manifestWorkLister, + spokeDynamicClient: spokeDynamicClient, + } + + return factory.New(). + WithInformersQueueKeyFunc(func(obj runtime.Object) string { + accessor, _ := meta.Accessor(obj) + return accessor.GetName() + }, manifestWorkInformer.Informer()). + WithSync(controller.sync).ToController("StaleManifestDeletionController", recorder) +} + +func (m *StaleManifestDeletionController) sync(ctx context.Context, controllerContext factory.SyncContext) error { + manifestWorkName := controllerContext.QueueKey() + klog.V(4).Infof("Reconciling ManifestWork %q", manifestWorkName) + + manifestWork, err := m.manifestWorkLister.Get(manifestWorkName) + if errors.IsNotFound(err) { + // work not found, could have been deleted, do nothing. + return nil + } + if err != nil { + return err + } + + return m.syncManifestWork(ctx, manifestWork) +} + +func (m *StaleManifestDeletionController) syncManifestWork(ctx context.Context, originalManifestWork *workapiv1.ManifestWork) error { + manifestWork := originalManifestWork.DeepCopy() + + // no work to do if we're deleted + if !manifestWork.DeletionTimestamp.IsZero() { + return nil + } + + // get the latest applied resources from the manifests in resource status. We get this from status instead of + // spec because manifests in spec are only resource templates, while resource status records the real resources + // maintained by the manifest work. + var appliedResources []workapiv1.AppliedManifestResourceMeta + for _, resourceStatus := range manifestWork.Status.ResourceStatus.Manifests { + gvr := schema.GroupVersionResource{Group: resourceStatus.ResourceMeta.Group, Version: resourceStatus.ResourceMeta.Version, Resource: resourceStatus.ResourceMeta.Resource} + if len(gvr.Resource) == 0 || len(gvr.Version) == 0 || len(resourceStatus.ResourceMeta.Name) == 0 { + continue + } + + appliedResources = append(appliedResources, workapiv1.AppliedManifestResourceMeta{ + Group: resourceStatus.ResourceMeta.Group, + Version: resourceStatus.ResourceMeta.Version, + Resource: resourceStatus.ResourceMeta.Resource, + Namespace: resourceStatus.ResourceMeta.Namespace, + Name: resourceStatus.ResourceMeta.Name, + }) + } + + // sort applied resources + sort.SliceStable(appliedResources, func(i, j int) bool { + switch { + case appliedResources[i].Group != appliedResources[j].Group: + return appliedResources[i].Group < appliedResources[j].Group + case appliedResources[i].Version != appliedResources[j].Version: + return appliedResources[i].Version < appliedResources[j].Version + case appliedResources[i].Resource != appliedResources[j].Resource: + return appliedResources[i].Resource < appliedResources[j].Resource + case appliedResources[i].Namespace != appliedResources[j].Namespace: + return appliedResources[i].Namespace < appliedResources[j].Namespace + default: + return appliedResources[i].Name < appliedResources[j].Name + } + }) + + // no work to do if applied resources are not changed + if reflect.DeepEqual(manifestWork.Status.AppliedResources, appliedResources) { + return nil + } + + // delete applied resources which are no longer maintained by manifest work + noLongerMaintainedResources := findUntrackedResources(manifestWork.Status.AppliedResources, appliedResources) + if errs := m.deleteAppliedResources(noLongerMaintainedResources); len(errs) != 0 { + return utilerrors.NewAggregate(errs) + } + + // update work status with latest applied resources. if this conflicts, we'll simply try again later + // for retrying update without reassessing the status can cause overwriting of valid information. + manifestWork.Status.AppliedResources = appliedResources + _, err := m.manifestWorkClient.UpdateStatus(ctx, manifestWork, metav1.UpdateOptions{}) + return err +} + +// deleteAppliedResources deletes all applied resources in the given resource meta array. +func (m *StaleManifestDeletionController) deleteAppliedResources(resources []workapiv1.AppliedManifestResourceMeta) []error { + var errs []error + for _, resource := range resources { + gvr := schema.GroupVersionResource{Group: resource.Group, Version: resource.Version, Resource: resource.Resource} + err := m.spokeDynamicClient.Resource(gvr).Namespace(resource.Namespace).Delete(context.TODO(), resource.Name, metav1.DeleteOptions{}) + switch { + case errors.IsNotFound(err): + // no-oop + case err != nil: + errs = append(errs, fmt.Errorf("Failed to delete resource %v with key %s/%s: %w", gvr, resource.Namespace, resource.Name, err)) + continue + } + klog.V(2).Infof("Successfully delete resource %v with key %s/%s", gvr, resource.Namespace, resource.Name) + } + + return errs +} + +// findUntrackedResources returns applied resources which are no longer tracked by manifestwork +func findUntrackedResources(appliedResources, newAppliedResources []workapiv1.AppliedManifestResourceMeta) []workapiv1.AppliedManifestResourceMeta { + var untracked []workapiv1.AppliedManifestResourceMeta + + resourceIndex := map[workapiv1.AppliedManifestResourceMeta]struct{}{} + for _, resource := range newAppliedResources { + resourceIndex[resource] = struct{}{} + } + + for _, resource := range appliedResources { + if _, ok := resourceIndex[resource]; !ok { + untracked = append(untracked, resource) + } + } + + return untracked +} diff --git a/pkg/spoke/controllers/deletioncontroller/deletion_controller_test.go b/pkg/spoke/controllers/deletioncontroller/deletion_controller_test.go new file mode 100644 index 000000000..2449520b6 --- /dev/null +++ b/pkg/spoke/controllers/deletioncontroller/deletion_controller_test.go @@ -0,0 +1,189 @@ +package deletioncontroller + +import ( + "context" + "reflect" + "testing" + + "github.com/davecgh/go-spew/spew" + fakeworkclient "github.com/open-cluster-management/api/client/work/clientset/versioned/fake" + workapiv1 "github.com/open-cluster-management/api/work/v1" + "github.com/open-cluster-management/work/pkg/spoke/spoketesting" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + fakedynamic "k8s.io/client-go/dynamic/fake" + clienttesting "k8s.io/client-go/testing" + "k8s.io/utils/diff" +) + +func newAppliedResource(group, version, resource, namespace, name string) workapiv1.AppliedManifestResourceMeta { + return workapiv1.AppliedManifestResourceMeta{ + Group: group, + Version: version, + Resource: resource, + Namespace: namespace, + Name: name, + } +} + +func newManifest(group, version, resource, namespace, name string) workapiv1.ManifestCondition { + return workapiv1.ManifestCondition{ + ResourceMeta: workapiv1.ManifestResourceMeta{ + Group: group, + Version: version, + Resource: resource, + Namespace: namespace, + Name: name, + }, + } +} + +func TestGarbageCollection(t *testing.T) { + cases := []struct { + name string + appliedResources []workapiv1.AppliedManifestResourceMeta + manifests []workapiv1.ManifestCondition + validateManifestWorkActions func(t *testing.T, actions []clienttesting.Action) + validateDynamicActions func(t *testing.T, actions []clienttesting.Action) + }{ + { + name: "skip when no applied resource changed", + appliedResources: []workapiv1.AppliedManifestResourceMeta{newAppliedResource("g1", "v1", "r1", "ns1", "n1")}, + manifests: []workapiv1.ManifestCondition{newManifest("g1", "v1", "r1", "ns1", "n1")}, + validateManifestWorkActions: func(t *testing.T, actions []clienttesting.Action) { + if len(actions) > 0 { + t.Fatal(spew.Sdump(actions)) + } + }, + validateDynamicActions: func(t *testing.T, actions []clienttesting.Action) { + if len(actions) > 0 { + t.Fatal(spew.Sdump(actions)) + } + }, + }, + { + name: "delete untracked resources", + appliedResources: []workapiv1.AppliedManifestResourceMeta{ + newAppliedResource("g1", "v1", "r1", "ns1", "n1"), + newAppliedResource("g2", "v2", "r2", "ns2", "n2"), + newAppliedResource("g3", "v3", "r3", "ns3", "n3"), + newAppliedResource("g4", "v4", "r4", "ns4", "n4"), + }, + manifests: []workapiv1.ManifestCondition{ + newManifest("g1", "v1", "r1", "ns1", "n1"), + newManifest("g2", "v2", "r2", "ns2", "n2"), + newManifest("g5", "v5", "r5", "ns5", "n5"), + newManifest("g6", "v6", "r6", "ns6", "n6"), + }, + validateManifestWorkActions: func(t *testing.T, actions []clienttesting.Action) { + if len(actions) != 1 { + t.Fatal(spew.Sdump(actions)) + } + work := actions[0].(clienttesting.UpdateAction).GetObject().(*workapiv1.ManifestWork) + if !reflect.DeepEqual(work.Status.AppliedResources, []workapiv1.AppliedManifestResourceMeta{ + newAppliedResource("g1", "v1", "r1", "ns1", "n1"), + newAppliedResource("g2", "v2", "r2", "ns2", "n2"), + newAppliedResource("g5", "v5", "r5", "ns5", "n5"), + newAppliedResource("g6", "v6", "r6", "ns6", "n6"), + }) { + t.Fatal(spew.Sdump(actions)) + } + }, + validateDynamicActions: func(t *testing.T, actions []clienttesting.Action) { + if len(actions) != 2 { + t.Fatal(spew.Sdump(actions)) + } + + action := actions[0].(clienttesting.DeleteAction) + resource, namespace, name := action.GetResource(), action.GetNamespace(), action.GetName() + if !reflect.DeepEqual(resource, schema.GroupVersionResource{Group: "g3", Version: "v3", Resource: "r3"}) || namespace != "ns3" || name != "n3" { + t.Fatal(spew.Sdump(actions)) + } + action = actions[1].(clienttesting.DeleteAction) + resource, namespace, name = action.GetResource(), action.GetNamespace(), action.GetName() + if !reflect.DeepEqual(resource, schema.GroupVersionResource{Group: "g4", Version: "v4", Resource: "r4"}) || namespace != "ns4" || name != "n4" { + t.Fatal(spew.Sdump(actions)) + } + }, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + testingWork, _ := spoketesting.NewManifestWork(0) + testingWork.Status.AppliedResources = c.appliedResources + testingWork.Status.ResourceStatus.Manifests = c.manifests + + fakeDynamicClient := fakedynamic.NewSimpleDynamicClient(runtime.NewScheme()) + fakeClient := fakeworkclient.NewSimpleClientset(testingWork) + controller := StaleManifestDeletionController{ + manifestWorkClient: fakeClient.WorkV1().ManifestWorks(testingWork.Namespace), + spokeDynamicClient: fakeDynamicClient, + } + + err := controller.syncManifestWork(context.TODO(), testingWork) + if err != nil { + t.Fatal(err) + } + c.validateManifestWorkActions(t, fakeClient.Actions()) + c.validateDynamicActions(t, fakeDynamicClient.Actions()) + }) + } + +} + +func TestFindUntrackedResources(t *testing.T) { + cases := []struct { + name string + appliedResources []workapiv1.AppliedManifestResourceMeta + newAppliedResources []workapiv1.AppliedManifestResourceMeta + expectedUntrackedResources []workapiv1.AppliedManifestResourceMeta + }{ + { + name: "no resource untracked", + appliedResources: nil, + newAppliedResources: []workapiv1.AppliedManifestResourceMeta{ + newAppliedResource("g1", "v1", "r1", "ns1", "n1"), + }, + expectedUntrackedResources: nil, + }, + { + name: "some of original resources untracked", + appliedResources: []workapiv1.AppliedManifestResourceMeta{ + newAppliedResource("g1", "v1", "r1", "ns1", "n1"), + newAppliedResource("g2", "v2", "r2", "ns2", "n2"), + }, + newAppliedResources: []workapiv1.AppliedManifestResourceMeta{ + newAppliedResource("g2", "v2", "r2", "ns2", "n2"), + newAppliedResource("g3", "v3", "r3", "ns3", "n3"), + }, + expectedUntrackedResources: []workapiv1.AppliedManifestResourceMeta{ + newAppliedResource("g1", "v1", "r1", "ns1", "n1"), + }, + }, + { + name: "all original resources untracked", + appliedResources: []workapiv1.AppliedManifestResourceMeta{ + newAppliedResource("g1", "v1", "r1", "ns1", "n1"), + newAppliedResource("g2", "v2", "r2", "ns2", "n2"), + }, + newAppliedResources: []workapiv1.AppliedManifestResourceMeta{ + newAppliedResource("g3", "v3", "r3", "ns3", "n3"), + newAppliedResource("g4", "v4", "r4", "ns4", "n4"), + }, + expectedUntrackedResources: []workapiv1.AppliedManifestResourceMeta{ + newAppliedResource("g1", "v1", "r1", "ns1", "n1"), + newAppliedResource("g2", "v2", "r2", "ns2", "n2"), + }, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + actual := findUntrackedResources(c.appliedResources, c.newAppliedResources) + if !reflect.DeepEqual(actual, c.expectedUntrackedResources) { + t.Errorf(diff.ObjectDiff(actual, c.expectedUntrackedResources)) + } + }) + } +} diff --git a/pkg/spoke/controllers/finalizercontroller/finalize_controller.go b/pkg/spoke/controllers/finalizercontroller/finalize_controller.go index 4be46f996..9f0129840 100644 --- a/pkg/spoke/controllers/finalizercontroller/finalize_controller.go +++ b/pkg/spoke/controllers/finalizercontroller/finalize_controller.go @@ -86,8 +86,21 @@ func (m *FinalizeController) syncManifestWork(ctx context.Context, originalManif return nil } + var err error + // Work is deleting, we remove its related resources on spoke cluster - if errs := m.cleanupResourceOfWork(manifestWork); len(errs) != 0 { + remaining, errs := m.cleanupResourceOfWork(manifestWork) + if len(manifestWork.Status.AppliedResources) != len(remaining) { + // update the status of the manifest work accordingly + manifestWork.Status.AppliedResources = remaining + + manifestWork, err = m.manifestWorkClient.UpdateStatus(ctx, manifestWork, metav1.UpdateOptions{}) + if err != nil { + errs = append(errs, fmt.Errorf( + "Failed to update status of ManifestWork %s/%s: %w", manifestWork.Namespace, manifestWork.Name, err)) + } + } + if len(errs) != 0 { return utilerrors.NewAggregate(errs) } @@ -97,42 +110,38 @@ func (m *FinalizeController) syncManifestWork(ctx context.Context, originalManif // compared with a case where this controller deletes it and another controller (or manifestwork) creates it. removeFinalizer(manifestWork, manifestWorkFinalizer) - _, err := m.manifestWorkClient.Update(ctx, manifestWork, metav1.UpdateOptions{}) + _, err = m.manifestWorkClient.Update(ctx, manifestWork, metav1.UpdateOptions{}) return err } -func (m *FinalizeController) cleanupResourceOfWork(work *workapiv1.ManifestWork) []error { +func (m *FinalizeController) cleanupResourceOfWork(work *workapiv1.ManifestWork) ([]workapiv1.AppliedManifestResourceMeta, []error) { klog.V(4).Infof("cleaning up %q", work.Name) + var remaining []workapiv1.AppliedManifestResourceMeta errs := []error{} - // TODO this can later be based on a list of all resources created by this manifest work - // not just the resources currently managed. This overlaps with the need to remove resources we have created - // separate from the application of current resources. - for _, resourceStatus := range work.Status.ResourceStatus.Manifests { - gvr := schema.GroupVersionResource{Group: resourceStatus.ResourceMeta.Group, Version: resourceStatus.ResourceMeta.Version, Resource: resourceStatus.ResourceMeta.Resource} - if len(gvr.Resource) == 0 || len(gvr.Version) == 0 || len(resourceStatus.ResourceMeta.Name) == 0 { - // without a resource or version, the request cannot be constructed, so we must not have created this either - continue - } + // delete all applied resources which are still tracked by the manifest work + for _, appliedResource := range work.Status.AppliedResources { + gvr := schema.GroupVersionResource{Group: appliedResource.Group, Version: appliedResource.Version, Resource: appliedResource.Resource} err := m.spokeDynamicClient. Resource(gvr). - Namespace(resourceStatus.ResourceMeta.Namespace). - Delete(context.TODO(), resourceStatus.ResourceMeta.Name, metav1.DeleteOptions{}) + Namespace(appliedResource.Namespace). + Delete(context.TODO(), appliedResource.Name, metav1.DeleteOptions{}) switch { case errors.IsNotFound(err): // no-oop case err != nil: + remaining = append(remaining, appliedResource) errs = append(errs, fmt.Errorf( "Failed to delete resource %v with key %s/%s: %w", - gvr, resourceStatus.ResourceMeta.Namespace, resourceStatus.ResourceMeta.Name, err)) + gvr, appliedResource.Namespace, appliedResource.Name, err)) continue } - klog.Infof("Successfully delete resource %v with key %s/%s", gvr, resourceStatus.ResourceMeta.Namespace, resourceStatus.ResourceMeta.Name) + klog.Infof("Successfully delete resource %v with key %s/%s", gvr, appliedResource.Namespace, appliedResource.Name) } - return errs + return remaining, errs } // removeFinalizer removes a finalizer from the list. It mutates its input. diff --git a/pkg/spoke/controllers/finalizercontroller/finalize_controller_test.go b/pkg/spoke/controllers/finalizercontroller/finalize_controller_test.go index 1d30435fd..942da07e8 100644 --- a/pkg/spoke/controllers/finalizercontroller/finalize_controller_test.go +++ b/pkg/spoke/controllers/finalizercontroller/finalize_controller_test.go @@ -20,7 +20,7 @@ func TestFinalize(t *testing.T) { cases := []struct { name string existingFinalizers []string - resourcesToRemove []workapiv1.ManifestResourceMeta + resourcesToRemove []workapiv1.AppliedManifestResourceMeta terminated bool validateManifestWorkActions func(t *testing.T, actions []clienttesting.Action) @@ -59,19 +59,24 @@ func TestFinalize(t *testing.T) { name: "delete resources", terminated: true, existingFinalizers: []string{"a", manifestWorkFinalizer, "b"}, - resourcesToRemove: []workapiv1.ManifestResourceMeta{ + resourcesToRemove: []workapiv1.AppliedManifestResourceMeta{ {Group: "g1", Version: "v1", Resource: "r1", Namespace: "", Name: "n1"}, {Group: "g2", Version: "v2", Resource: "r2", Namespace: "ns2", Name: "n2"}, {Group: "g3", Version: "v3", Resource: "r3", Namespace: "ns3", Name: "n3"}, {Group: "g4", Version: "v4", Resource: "r4", Namespace: "", Name: "n4"}, }, validateManifestWorkActions: func(t *testing.T, actions []clienttesting.Action) { - if len(actions) != 1 { + if len(actions) != 2 { t.Fatal(spew.Sdump(actions)) } + work := actions[0].(clienttesting.UpdateAction).GetObject().(*workapiv1.ManifestWork) + if len(work.Status.AppliedResources) != 0 { + t.Fatal(spew.Sdump(actions[0])) + } + work = actions[1].(clienttesting.UpdateAction).GetObject().(*workapiv1.ManifestWork) if !reflect.DeepEqual(work.Finalizers, []string{"a", "b"}) { - t.Fatal(spew.Sdump(actions)) + t.Fatal(spew.Sdump(actions[1])) } }, validateDynamicActions: func(t *testing.T, actions []clienttesting.Action) { @@ -112,7 +117,7 @@ func TestFinalize(t *testing.T) { testingWork.DeletionTimestamp = &now } for _, curr := range c.resourcesToRemove { - testingWork.Status.ResourceStatus.Manifests = append(testingWork.Status.ResourceStatus.Manifests, workapiv1.ManifestCondition{ResourceMeta: curr}) + testingWork.Status.AppliedResources = append(testingWork.Status.AppliedResources, curr) } fakeDynamicClient := fakedynamic.NewSimpleDynamicClient(runtime.NewScheme()) diff --git a/pkg/spoke/spokeagent.go b/pkg/spoke/spokeagent.go index bdaeaa600..6cd081eab 100644 --- a/pkg/spoke/spokeagent.go +++ b/pkg/spoke/spokeagent.go @@ -4,9 +4,9 @@ import ( "context" "time" - "github.com/open-cluster-management/work/pkg/spoke/controllers/manifestcontroller" - + "github.com/open-cluster-management/work/pkg/spoke/controllers/deletioncontroller" "github.com/open-cluster-management/work/pkg/spoke/controllers/finalizercontroller" + "github.com/open-cluster-management/work/pkg/spoke/controllers/manifestcontroller" "github.com/openshift/library-go/pkg/controller/controllercmd" "github.com/spf13/cobra" @@ -105,9 +105,18 @@ func (o *WorkloadAgentOptions) RunWorkloadAgent(ctx context.Context, controllerC workInformerFactory.Work().V1().ManifestWorks().Lister().ManifestWorks(o.SpokeClusterName), ) + staleManifestDeletionController := deletioncontroller.NewStaleManifestDeletionController( + controllerContext.EventRecorder, + spokeDynamicClient, + hubWorkClient.WorkV1().ManifestWorks(o.SpokeClusterName), + workInformerFactory.Work().V1().ManifestWorks(), + workInformerFactory.Work().V1().ManifestWorks().Lister().ManifestWorks(o.SpokeClusterName), + ) + go workInformerFactory.Start(ctx.Done()) go addFinalizerController.Run(ctx, 1) go finalizeController.Run(ctx, 1) + go staleManifestDeletionController.Run(ctx, 1) go manifestWorkController.Run(ctx, 1) <-ctx.Done() return nil diff --git a/vendor/github.com/open-cluster-management/api/work/v1/0000_00_work.open-cluster-management.io_manifestworks.crd.yaml b/vendor/github.com/open-cluster-management/api/work/v1/0000_00_work.open-cluster-management.io_manifestworks.crd.yaml index d71305e8b..0dfcc943f 100644 --- a/vendor/github.com/open-cluster-management/api/work/v1/0000_00_work.open-cluster-management.io_manifestworks.crd.yaml +++ b/vendor/github.com/open-cluster-management/api/work/v1/0000_00_work.open-cluster-management.io_manifestworks.crd.yaml @@ -59,6 +59,39 @@ spec: description: Status represents the current status of work type: object properties: + appliedResources: + description: AppliedResources represents a list of resources defined + within the manifestwork that are applied. Only resources with valid + GroupVersionResource, namespace, and name are suitable. An item in + this slice is deleted when there is no mapped manifest in manifestwork.Spec + or by finalizer. The resource relating to the item will also be removed + from spoke cluster. The deleted resource may still be present until + the finalizers for that resource are finished. However, the resource + will not be undeleted, so it can be removed from this list and eventual + consistency is preserved. + type: array + items: + description: AppliedManifestResourceMeta represents the gvr, name + and namespace of a resource. Since these resources have been created, + they must have valid group, version, resource, namespace, and name. + type: object + properties: + group: + description: Group is the API Group of the kubernetes resource + type: string + name: + description: Name is the name of the kubernetes resource + type: string + namespace: + description: Name is the namespace of the kubernetes resource, + empty string indicates it is a cluster scoped resource. + type: string + resource: + description: Resource is the resource name of the kubernetes resource + type: string + version: + description: Version is the version of the kubernetes resource + type: string conditions: description: 'Conditions contains the different condition statuses for this work. Valid condition types are: 1. Applied represents workload diff --git a/vendor/github.com/open-cluster-management/api/work/v1/generated.pb.go b/vendor/github.com/open-cluster-management/api/work/v1/generated.pb.go index abaac76a6..32eccd296 100644 --- a/vendor/github.com/open-cluster-management/api/work/v1/generated.pb.go +++ b/vendor/github.com/open-cluster-management/api/work/v1/generated.pb.go @@ -28,10 +28,38 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +func (m *AppliedManifestResourceMeta) Reset() { *m = AppliedManifestResourceMeta{} } +func (*AppliedManifestResourceMeta) ProtoMessage() {} +func (*AppliedManifestResourceMeta) Descriptor() ([]byte, []int) { + return fileDescriptor_97234883da270a20, []int{0} +} +func (m *AppliedManifestResourceMeta) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AppliedManifestResourceMeta) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *AppliedManifestResourceMeta) XXX_Merge(src proto.Message) { + xxx_messageInfo_AppliedManifestResourceMeta.Merge(m, src) +} +func (m *AppliedManifestResourceMeta) XXX_Size() int { + return m.Size() +} +func (m *AppliedManifestResourceMeta) XXX_DiscardUnknown() { + xxx_messageInfo_AppliedManifestResourceMeta.DiscardUnknown(m) +} + +var xxx_messageInfo_AppliedManifestResourceMeta proto.InternalMessageInfo + func (m *Manifest) Reset() { *m = Manifest{} } func (*Manifest) ProtoMessage() {} func (*Manifest) Descriptor() ([]byte, []int) { - return fileDescriptor_97234883da270a20, []int{0} + return fileDescriptor_97234883da270a20, []int{1} } func (m *Manifest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -59,7 +87,7 @@ var xxx_messageInfo_Manifest proto.InternalMessageInfo func (m *ManifestCondition) Reset() { *m = ManifestCondition{} } func (*ManifestCondition) ProtoMessage() {} func (*ManifestCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_97234883da270a20, []int{1} + return fileDescriptor_97234883da270a20, []int{2} } func (m *ManifestCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -87,7 +115,7 @@ var xxx_messageInfo_ManifestCondition proto.InternalMessageInfo func (m *ManifestResourceMeta) Reset() { *m = ManifestResourceMeta{} } func (*ManifestResourceMeta) ProtoMessage() {} func (*ManifestResourceMeta) Descriptor() ([]byte, []int) { - return fileDescriptor_97234883da270a20, []int{2} + return fileDescriptor_97234883da270a20, []int{3} } func (m *ManifestResourceMeta) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -115,7 +143,7 @@ var xxx_messageInfo_ManifestResourceMeta proto.InternalMessageInfo func (m *ManifestResourceStatus) Reset() { *m = ManifestResourceStatus{} } func (*ManifestResourceStatus) ProtoMessage() {} func (*ManifestResourceStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_97234883da270a20, []int{3} + return fileDescriptor_97234883da270a20, []int{4} } func (m *ManifestResourceStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -143,7 +171,7 @@ var xxx_messageInfo_ManifestResourceStatus proto.InternalMessageInfo func (m *ManifestWork) Reset() { *m = ManifestWork{} } func (*ManifestWork) ProtoMessage() {} func (*ManifestWork) Descriptor() ([]byte, []int) { - return fileDescriptor_97234883da270a20, []int{4} + return fileDescriptor_97234883da270a20, []int{5} } func (m *ManifestWork) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -171,7 +199,7 @@ var xxx_messageInfo_ManifestWork proto.InternalMessageInfo func (m *ManifestWorkList) Reset() { *m = ManifestWorkList{} } func (*ManifestWorkList) ProtoMessage() {} func (*ManifestWorkList) Descriptor() ([]byte, []int) { - return fileDescriptor_97234883da270a20, []int{5} + return fileDescriptor_97234883da270a20, []int{6} } func (m *ManifestWorkList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -199,7 +227,7 @@ var xxx_messageInfo_ManifestWorkList proto.InternalMessageInfo func (m *ManifestWorkSpec) Reset() { *m = ManifestWorkSpec{} } func (*ManifestWorkSpec) ProtoMessage() {} func (*ManifestWorkSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_97234883da270a20, []int{6} + return fileDescriptor_97234883da270a20, []int{7} } func (m *ManifestWorkSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -227,7 +255,7 @@ var xxx_messageInfo_ManifestWorkSpec proto.InternalMessageInfo func (m *ManifestWorkStatus) Reset() { *m = ManifestWorkStatus{} } func (*ManifestWorkStatus) ProtoMessage() {} func (*ManifestWorkStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_97234883da270a20, []int{7} + return fileDescriptor_97234883da270a20, []int{8} } func (m *ManifestWorkStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -255,7 +283,7 @@ var xxx_messageInfo_ManifestWorkStatus proto.InternalMessageInfo func (m *ManifestsTemplate) Reset() { *m = ManifestsTemplate{} } func (*ManifestsTemplate) ProtoMessage() {} func (*ManifestsTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_97234883da270a20, []int{8} + return fileDescriptor_97234883da270a20, []int{9} } func (m *ManifestsTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -283,7 +311,7 @@ var xxx_messageInfo_ManifestsTemplate proto.InternalMessageInfo func (m *StatusCondition) Reset() { *m = StatusCondition{} } func (*StatusCondition) ProtoMessage() {} func (*StatusCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_97234883da270a20, []int{9} + return fileDescriptor_97234883da270a20, []int{10} } func (m *StatusCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -309,6 +337,7 @@ func (m *StatusCondition) XXX_DiscardUnknown() { var xxx_messageInfo_StatusCondition proto.InternalMessageInfo func init() { + proto.RegisterType((*AppliedManifestResourceMeta)(nil), "github.com.open_cluster_management.api.work.v1.AppliedManifestResourceMeta") proto.RegisterType((*Manifest)(nil), "github.com.open_cluster_management.api.work.v1.Manifest") proto.RegisterType((*ManifestCondition)(nil), "github.com.open_cluster_management.api.work.v1.ManifestCondition") proto.RegisterType((*ManifestResourceMeta)(nil), "github.com.open_cluster_management.api.work.v1.ManifestResourceMeta") @@ -326,64 +355,117 @@ func init() { } var fileDescriptor_97234883da270a20 = []byte{ - // 907 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4b, 0x6f, 0x1b, 0x45, - 0x1c, 0xf7, 0x6e, 0xe3, 0xc4, 0x99, 0x98, 0xb4, 0x1d, 0x55, 0x95, 0x95, 0xc3, 0x26, 0x5a, 0x24, - 0x14, 0x10, 0x99, 0x25, 0x11, 0x42, 0x3d, 0x20, 0x1e, 0x0b, 0x14, 0x21, 0x9a, 0x56, 0x9a, 0x46, - 0x54, 0x42, 0x88, 0x32, 0x59, 0x4f, 0x37, 0x53, 0x7b, 0x67, 0x56, 0x33, 0x63, 0x97, 0x5c, 0x2a, - 0x24, 0x24, 0xc4, 0x81, 0x03, 0xe2, 0xb3, 0xf0, 0x01, 0x38, 0xe6, 0x58, 0x89, 0x4b, 0x4f, 0x11, - 0x31, 0xdf, 0x82, 0x13, 0x9a, 0xd9, 0xd9, 0x87, 0xed, 0x54, 0x4d, 0x1d, 0xa9, 0xa7, 0x64, 0xff, - 0x8f, 0xdf, 0xef, 0xff, 0x1e, 0x83, 0x8f, 0x52, 0xa6, 0x8f, 0x46, 0x87, 0x28, 0x11, 0x59, 0x24, - 0x72, 0xca, 0x77, 0x92, 0xe1, 0x48, 0x69, 0x2a, 0x77, 0x32, 0xc2, 0x49, 0x4a, 0x33, 0xca, 0x75, - 0x44, 0x72, 0x16, 0x3d, 0x11, 0x72, 0x10, 0x8d, 0x77, 0xa3, 0x94, 0x72, 0x2a, 0x89, 0xa6, 0x7d, - 0x94, 0x4b, 0xa1, 0x05, 0x44, 0xb5, 0x3f, 0x32, 0xfe, 0x0f, 0x9d, 0xff, 0xc3, 0xda, 0x1f, 0x91, - 0x9c, 0x21, 0xe3, 0x8f, 0xc6, 0xbb, 0x1b, 0x3b, 0x0d, 0xbe, 0x54, 0xa4, 0x22, 0xb2, 0x30, 0x87, - 0xa3, 0x47, 0xf6, 0xcb, 0x7e, 0xd8, 0xff, 0x0a, 0xf8, 0x8d, 0xf7, 0x07, 0xb7, 0x14, 0x62, 0xc2, - 0x84, 0x90, 0x91, 0xe4, 0x88, 0x71, 0x2a, 0x8f, 0xa3, 0x7c, 0x90, 0x1a, 0x81, 0x8a, 0x32, 0xaa, - 0xc9, 0x39, 0x41, 0x6d, 0x44, 0x2f, 0xf2, 0x92, 0x23, 0xae, 0x59, 0x46, 0xe7, 0x1c, 0x3e, 0x78, - 0x99, 0x83, 0x4a, 0x8e, 0x68, 0x46, 0x66, 0xfd, 0x42, 0x05, 0x3a, 0xfb, 0x84, 0xb3, 0x47, 0x54, - 0x69, 0x98, 0x82, 0xae, 0x24, 0x4f, 0xbe, 0xf8, 0x51, 0x53, 0xae, 0x98, 0xe0, 0x3d, 0x6f, 0xcb, - 0xdb, 0x5e, 0xdb, 0xdb, 0x41, 0x05, 0x34, 0x6a, 0x42, 0xa3, 0x7c, 0x90, 0x22, 0x07, 0x8d, 0x70, - 0xc3, 0x29, 0xbe, 0x71, 0x72, 0xba, 0xd9, 0x9a, 0x9c, 0x6e, 0x76, 0x9b, 0x52, 0x3c, 0x05, 0x1c, - 0xfe, 0xea, 0x83, 0xeb, 0x25, 0xeb, 0x67, 0x82, 0xf7, 0x99, 0x66, 0x82, 0xc3, 0xa7, 0xa0, 0x2b, - 0xa9, 0x12, 0x23, 0x99, 0xd0, 0x7d, 0xaa, 0x89, 0xa3, 0xff, 0xfc, 0x15, 0xfb, 0x83, 0x4a, 0x60, - 0xdc, 0xc0, 0x6a, 0x44, 0xd5, 0x90, 0xe2, 0x29, 0x3e, 0xa8, 0x00, 0x48, 0xca, 0x60, 0x54, 0xcf, - 0xdf, 0xba, 0xb2, 0xbd, 0xb6, 0xf7, 0xf1, 0xab, 0xb2, 0xdf, 0xd7, 0x44, 0x8f, 0x54, 0x95, 0x54, - 0x0c, 0x1d, 0x31, 0xa8, 0x44, 0x0a, 0x37, 0x68, 0xc2, 0x3f, 0x7d, 0x70, 0xe3, 0xbc, 0x88, 0xe1, - 0xdb, 0x60, 0x45, 0xc8, 0x3e, 0xe3, 0x64, 0x68, 0x0b, 0xd1, 0x8e, 0xaf, 0x3a, 0xa4, 0x95, 0x7b, - 0x85, 0x18, 0x97, 0x7a, 0xf8, 0x26, 0x68, 0xa7, 0x52, 0x8c, 0xf2, 0x9e, 0xbf, 0xe5, 0x6d, 0xaf, - 0xc6, 0x6f, 0x38, 0xc3, 0xf6, 0x97, 0x46, 0x88, 0x0b, 0x9d, 0xc1, 0x1b, 0x53, 0x69, 0xfb, 0x7a, - 0xc5, 0x9a, 0x55, 0x78, 0xdf, 0x14, 0x62, 0x5c, 0xea, 0xe1, 0x16, 0x58, 0x1a, 0x30, 0xde, 0xef, - 0x2d, 0x59, 0xbb, 0xae, 0xb3, 0x5b, 0xfa, 0x9a, 0xf1, 0x3e, 0xb6, 0x1a, 0xf8, 0x2e, 0xe8, 0x94, - 0xa5, 0xeb, 0xb5, 0xad, 0xd5, 0x35, 0x67, 0xd5, 0x29, 0x93, 0xc0, 0x95, 0x85, 0xc1, 0xe3, 0x24, - 0xa3, 0xbd, 0xe5, 0x69, 0xbc, 0xbb, 0x24, 0xa3, 0xd8, 0x6a, 0x60, 0x04, 0x56, 0xcd, 0x5f, 0x95, - 0x93, 0x84, 0xf6, 0x56, 0xac, 0xd9, 0x75, 0x67, 0xb6, 0x7a, 0xb7, 0x54, 0xe0, 0xda, 0x26, 0xfc, - 0xcd, 0x03, 0x37, 0x67, 0xcb, 0x56, 0x94, 0x1e, 0x4a, 0xb0, 0x9a, 0x39, 0x4d, 0xd9, 0xc5, 0x4f, - 0x17, 0x9d, 0xa1, 0xba, 0x8f, 0x55, 0x38, 0xa5, 0x4a, 0xe1, 0x9a, 0x26, 0xfc, 0xcb, 0x07, 0xdd, - 0x52, 0xf1, 0x40, 0xc8, 0x01, 0xfc, 0x01, 0x74, 0xcc, 0x6a, 0xf7, 0x49, 0x35, 0xc7, 0xef, 0xbd, - 0x70, 0x8d, 0xcc, 0x21, 0x40, 0xc6, 0xda, 0x30, 0xdf, 0x3b, 0x7c, 0x4c, 0x13, 0x6d, 0x67, 0xb6, - 0x1a, 0x9d, 0x5a, 0x86, 0x2b, 0x54, 0x78, 0x08, 0x96, 0x54, 0x4e, 0x13, 0xdb, 0xf3, 0xb5, 0xbd, - 0x4f, 0x16, 0xcd, 0xd0, 0x44, 0x7b, 0x3f, 0xa7, 0x49, 0xdd, 0x16, 0xf3, 0x85, 0x2d, 0x36, 0x7c, - 0x0c, 0x96, 0x95, 0x2d, 0xaa, 0x1d, 0x99, 0xb5, 0xbd, 0xf8, 0x52, 0x2c, 0x16, 0x29, 0x5e, 0x77, - 0x3c, 0xcb, 0xc5, 0x37, 0x76, 0x0c, 0xe1, 0xdf, 0x1e, 0xb8, 0xd6, 0x34, 0xbf, 0xc3, 0x94, 0x86, - 0xdf, 0xcd, 0x95, 0x11, 0x5d, 0xac, 0x8c, 0xc6, 0xdb, 0x16, 0xb1, 0x9a, 0xcb, 0x52, 0xd2, 0x28, - 0x21, 0x01, 0x6d, 0xa6, 0x69, 0x56, 0x4e, 0xc9, 0x87, 0x97, 0xc9, 0xae, 0xde, 0xba, 0xaf, 0x0c, - 0x24, 0x2e, 0x90, 0xc3, 0x9f, 0x67, 0xb2, 0x32, 0xc5, 0x85, 0x02, 0x74, 0x0c, 0xc4, 0x50, 0x90, - 0xbe, 0xcb, 0x6a, 0xe1, 0x01, 0x55, 0x07, 0x34, 0xcb, 0x87, 0x44, 0xd3, 0x3a, 0xd1, 0x07, 0x0e, - 0x1a, 0x57, 0x24, 0xe1, 0x1f, 0x3e, 0x80, 0xf3, 0xad, 0x98, 0x39, 0x78, 0xde, 0x6b, 0x39, 0x78, - 0xf0, 0x17, 0x0f, 0xac, 0xcb, 0xa9, 0x8d, 0x75, 0x23, 0x7c, 0xfb, 0xb2, 0x87, 0xde, 0x0d, 0xd8, - 0x4d, 0x17, 0xc0, 0xfa, 0xb4, 0x1c, 0xcf, 0xb0, 0x86, 0x4f, 0xeb, 0x37, 0xa8, 0xaa, 0x22, 0x64, - 0xcd, 0xe3, 0x51, 0x54, 0xe4, 0xd6, 0xa2, 0x71, 0xbd, 0xe4, 0x66, 0x9c, 0xfa, 0xe0, 0xea, 0x4c, - 0xf1, 0xcc, 0xa5, 0xd4, 0xc7, 0x39, 0xb5, 0x53, 0xd1, 0xb8, 0x94, 0x07, 0xc7, 0x39, 0xc5, 0x56, - 0x03, 0xbf, 0xaf, 0x56, 0xb2, 0x38, 0xf6, 0xb7, 0xa7, 0xd7, 0xe9, 0xbf, 0xd3, 0xcd, 0x0b, 0xfd, - 0xe0, 0x40, 0x15, 0xe7, 0xf4, 0x1a, 0xc2, 0x31, 0x80, 0x43, 0xa2, 0xf4, 0x81, 0x24, 0x5c, 0x59, - 0xfd, 0x01, 0xcb, 0xa8, 0x5b, 0xff, 0x77, 0x2e, 0xb6, 0x7b, 0xc6, 0x23, 0xde, 0x70, 0x71, 0xc1, - 0x3b, 0x73, 0x68, 0xf8, 0x1c, 0x06, 0xf8, 0x16, 0x58, 0x96, 0x94, 0x28, 0xc1, 0xdd, 0xab, 0x53, - 0x9d, 0x09, 0x6c, 0xa5, 0xd8, 0x69, 0xcd, 0x33, 0x96, 0x51, 0xa5, 0x48, 0x5a, 0x3e, 0x3c, 0xd5, - 0x33, 0xb6, 0x5f, 0x88, 0x71, 0xa9, 0x8f, 0xb7, 0x4f, 0xce, 0x82, 0xd6, 0xb3, 0xb3, 0xa0, 0xf5, - 0xfc, 0x2c, 0x68, 0xfd, 0x34, 0x09, 0xbc, 0x93, 0x49, 0xe0, 0x3d, 0x9b, 0x04, 0xde, 0xf3, 0x49, - 0xe0, 0xfd, 0x33, 0x09, 0xbc, 0xdf, 0xff, 0x0d, 0x5a, 0xdf, 0xfa, 0xe3, 0xdd, 0xff, 0x03, 0x00, - 0x00, 0xff, 0xff, 0x49, 0x87, 0xf8, 0xee, 0x43, 0x0a, 0x00, 0x00, + // 978 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4d, 0x6f, 0x1b, 0x45, + 0x18, 0xf6, 0x3a, 0x76, 0xe2, 0x4c, 0x4c, 0x9a, 0x8e, 0xaa, 0xca, 0x0a, 0xd2, 0x26, 0x5a, 0x24, + 0x94, 0x22, 0x32, 0x4b, 0x22, 0x84, 0x7a, 0x40, 0x40, 0x0c, 0x14, 0xa1, 0x36, 0xad, 0x34, 0x8d, + 0xa8, 0x84, 0x10, 0x65, 0xb2, 0x9e, 0x6e, 0xa6, 0xf6, 0xee, 0xac, 0x66, 0xc6, 0x2e, 0xb9, 0x54, + 0x48, 0x48, 0x88, 0x03, 0x07, 0xf8, 0x13, 0xfc, 0x02, 0x7e, 0x00, 0xc7, 0x1c, 0x2b, 0x71, 0xe9, + 0x29, 0x22, 0xe6, 0xce, 0x0f, 0xe0, 0x84, 0x66, 0x76, 0xf6, 0xc3, 0xeb, 0x94, 0x38, 0x8e, 0xc4, + 0xc9, 0xde, 0xf7, 0xeb, 0x79, 0xe7, 0x79, 0x9f, 0x7d, 0x67, 0xc1, 0x07, 0x21, 0x53, 0x47, 0xc3, + 0x43, 0x14, 0xf0, 0xc8, 0xe7, 0x09, 0x8d, 0xb7, 0x83, 0xc1, 0x50, 0x2a, 0x2a, 0xb6, 0x23, 0x12, + 0x93, 0x90, 0x46, 0x34, 0x56, 0x3e, 0x49, 0x98, 0xff, 0x8c, 0x8b, 0xbe, 0x3f, 0xda, 0xf1, 0x43, + 0x1a, 0x53, 0x41, 0x14, 0xed, 0xa1, 0x44, 0x70, 0xc5, 0x21, 0x2a, 0xf2, 0x91, 0xce, 0x7f, 0x6c, + 0xf3, 0x1f, 0x17, 0xf9, 0x88, 0x24, 0x0c, 0xe9, 0x7c, 0x34, 0xda, 0x59, 0xdf, 0x2e, 0xe1, 0x85, + 0x3c, 0xe4, 0xbe, 0x29, 0x73, 0x38, 0x7c, 0x62, 0x9e, 0xcc, 0x83, 0xf9, 0x97, 0x96, 0x5f, 0x7f, + 0xb7, 0x7f, 0x5b, 0x22, 0xc6, 0x75, 0x0b, 0x11, 0x09, 0x8e, 0x58, 0x4c, 0xc5, 0xb1, 0x9f, 0xf4, + 0x43, 0x6d, 0x90, 0x7e, 0x44, 0x15, 0x39, 0xa7, 0xa9, 0x75, 0xff, 0x55, 0x59, 0x62, 0x18, 0x2b, + 0x16, 0xd1, 0xa9, 0x84, 0xf7, 0x2e, 0x4a, 0x90, 0xc1, 0x11, 0x8d, 0x48, 0x35, 0xcf, 0xfb, 0xdb, + 0x01, 0xaf, 0xef, 0x25, 0xc9, 0x80, 0xd1, 0xde, 0x3e, 0x89, 0xd9, 0x13, 0x2a, 0x15, 0xa6, 0x92, + 0x0f, 0x45, 0x40, 0xf7, 0xa9, 0x22, 0xf0, 0x0d, 0xd0, 0x0c, 0x05, 0x1f, 0x26, 0x1d, 0x67, 0xd3, + 0xd9, 0x5a, 0xee, 0xbe, 0x76, 0x72, 0xba, 0x51, 0x1b, 0x9f, 0x6e, 0x34, 0x3f, 0xd3, 0x46, 0x9c, + 0xfa, 0xe0, 0x2d, 0xb0, 0x34, 0xa2, 0x42, 0x32, 0x1e, 0x77, 0xea, 0x26, 0xec, 0x9a, 0x0d, 0x5b, + 0xfa, 0x22, 0x35, 0xe3, 0xcc, 0x0f, 0xdf, 0x06, 0x2d, 0x61, 0xeb, 0x77, 0x16, 0x4c, 0xec, 0x9a, + 0x8d, 0x6d, 0x65, 0xb8, 0x38, 0x8f, 0x80, 0x9b, 0xa0, 0x11, 0x93, 0x88, 0x76, 0x1a, 0x26, 0xb2, + 0x6d, 0x23, 0x1b, 0xf7, 0x49, 0x44, 0xb1, 0xf1, 0x40, 0x1f, 0x2c, 0xeb, 0x5f, 0x99, 0x90, 0x80, + 0x76, 0x9a, 0x26, 0xec, 0xba, 0x0d, 0x5b, 0xbe, 0x9f, 0x39, 0x70, 0x11, 0xe3, 0x49, 0xd0, 0xca, + 0x0e, 0x0a, 0x43, 0xd0, 0x16, 0xe4, 0xd9, 0xa7, 0xdf, 0x2a, 0x1a, 0x9b, 0xe6, 0xf5, 0x19, 0x57, + 0x76, 0xb7, 0x51, 0xca, 0x25, 0x2a, 0x73, 0x89, 0x92, 0x7e, 0x88, 0x2c, 0x97, 0x08, 0x97, 0x92, + 0xba, 0x37, 0x2c, 0x5c, 0xbb, 0x6c, 0xc5, 0x13, 0x85, 0xbd, 0x1f, 0xeb, 0xe0, 0x7a, 0x86, 0xfa, + 0x31, 0x8f, 0x7b, 0x4c, 0x69, 0x2e, 0x9e, 0x83, 0xb6, 0x28, 0x71, 0x6d, 0xe1, 0x3f, 0xb9, 0xa4, + 0x20, 0xd1, 0x79, 0x73, 0x2b, 0x75, 0x55, 0xb2, 0xe2, 0x09, 0x3c, 0x28, 0x01, 0x08, 0xb2, 0x66, + 0x64, 0xa7, 0xbe, 0xb9, 0xb0, 0xb5, 0xb2, 0xfb, 0xe1, 0x65, 0xd1, 0x1f, 0x2a, 0xa2, 0x86, 0x32, + 0x3f, 0x54, 0x17, 0x5a, 0x60, 0x90, 0x9b, 0x24, 0x2e, 0xc1, 0x78, 0xbf, 0xd5, 0xc1, 0x8d, 0x73, + 0x95, 0x76, 0x0b, 0x2c, 0x71, 0xd1, 0x63, 0x31, 0x19, 0x18, 0x22, 0x9a, 0x85, 0x88, 0x1e, 0xa4, + 0x66, 0x9c, 0xf9, 0x0b, 0x51, 0xd6, 0x67, 0x13, 0xe5, 0xc2, 0x05, 0xa2, 0xdc, 0x04, 0x8d, 0x3e, + 0x8b, 0x7b, 0x55, 0x99, 0xdd, 0x65, 0x71, 0x0f, 0x1b, 0xcf, 0x84, 0x6c, 0x9b, 0x33, 0xcb, 0x76, + 0x71, 0x36, 0xd9, 0x2e, 0xcd, 0x20, 0xdb, 0x9f, 0x1c, 0x70, 0xb3, 0x4a, 0x5b, 0x4a, 0x3d, 0x14, + 0x60, 0x39, 0xb2, 0x9e, 0x6c, 0x8a, 0x7b, 0xf3, 0x6a, 0xa8, 0x98, 0x63, 0xde, 0x4e, 0xe6, 0x92, + 0xb8, 0x80, 0xf1, 0x7e, 0xaf, 0x83, 0x76, 0xe6, 0x78, 0xc4, 0x45, 0x1f, 0x7e, 0x03, 0x5a, 0x7a, + 0x97, 0xf5, 0x48, 0xae, 0xe3, 0x77, 0x5e, 0xf9, 0x1a, 0xe9, 0xcd, 0x87, 0x74, 0xb4, 0x46, 0x7e, + 0x70, 0xf8, 0x94, 0x06, 0xca, 0x68, 0x36, 0x97, 0x4e, 0x61, 0xc3, 0x79, 0x55, 0x78, 0x08, 0x1a, + 0x32, 0xa1, 0x81, 0x99, 0xf9, 0xca, 0xee, 0x47, 0xf3, 0x9e, 0x50, 0x77, 0xfb, 0x30, 0xa1, 0x41, + 0x31, 0x16, 0xfd, 0x84, 0x4d, 0x6d, 0xf8, 0x14, 0x2c, 0x4a, 0x43, 0xaa, 0x91, 0xcc, 0xca, 0x6e, + 0xf7, 0x4a, 0x28, 0xa6, 0x52, 0x77, 0xd5, 0xe2, 0x2c, 0xa6, 0xcf, 0xd8, 0x22, 0x78, 0x7f, 0x38, + 0x60, 0xad, 0x1c, 0x7e, 0x8f, 0x49, 0x05, 0xbf, 0x9a, 0xa2, 0x11, 0xcd, 0x46, 0xa3, 0xce, 0x36, + 0x24, 0xe6, 0xba, 0xcc, 0x2c, 0x25, 0x0a, 0x09, 0x68, 0x32, 0x45, 0xa3, 0x4c, 0x25, 0xef, 0x5f, + 0xe5, 0x74, 0xc5, 0x5b, 0xf7, 0xb9, 0x2e, 0x89, 0xd3, 0xca, 0xde, 0xf7, 0x95, 0x53, 0x69, 0x72, + 0x21, 0x07, 0x2d, 0x5d, 0x62, 0xc0, 0x49, 0xcf, 0x9e, 0x6a, 0x6e, 0x81, 0xca, 0x03, 0x1a, 0x25, + 0x03, 0xa2, 0x68, 0x71, 0xd0, 0x47, 0xb6, 0x34, 0xce, 0x41, 0xbc, 0x5f, 0x17, 0x00, 0x9c, 0x1e, + 0x45, 0x65, 0xe1, 0x39, 0xff, 0xcb, 0xc2, 0x83, 0x3f, 0x38, 0x60, 0x55, 0x4c, 0xbc, 0xb1, 0x56, + 0xc2, 0x77, 0xae, 0xba, 0xe8, 0xad, 0xc0, 0x6e, 0xda, 0x06, 0x56, 0x27, 0xed, 0xb8, 0x82, 0x0a, + 0x7f, 0x71, 0xc0, 0x1a, 0x49, 0xaf, 0xfa, 0x2c, 0x52, 0xeb, 0x5c, 0x93, 0x70, 0xf7, 0xb2, 0xad, + 0xfc, 0xc7, 0x27, 0x43, 0xb7, 0x63, 0xfb, 0x59, 0xdb, 0xab, 0x80, 0xe1, 0x29, 0x78, 0xef, 0x79, + 0x71, 0x2f, 0xe6, 0x93, 0x85, 0xac, 0xbc, 0xd0, 0xd2, 0x29, 0xdd, 0x9e, 0x97, 0xab, 0x0b, 0xf6, + 0xd8, 0x69, 0x1d, 0x5c, 0xab, 0x0c, 0x54, 0x6f, 0x6f, 0x75, 0x9c, 0x50, 0xfb, 0xc5, 0x93, 0xaf, + 0x89, 0x83, 0xe3, 0x84, 0x62, 0xe3, 0x81, 0x5f, 0xe7, 0x6b, 0x22, 0xbd, 0x80, 0xee, 0x4c, 0xbe, + 0xe2, 0xff, 0x9c, 0x6e, 0xcc, 0xf4, 0xd5, 0x87, 0x72, 0xcc, 0xc9, 0xd5, 0x00, 0x47, 0x00, 0x0e, + 0x88, 0x54, 0x07, 0x82, 0xc4, 0xd2, 0xf8, 0x0f, 0x58, 0x44, 0xed, 0x4a, 0x7a, 0x6b, 0xb6, 0x7d, + 0xa0, 0x33, 0xba, 0xeb, 0xb6, 0x2f, 0x78, 0x6f, 0xaa, 0x1a, 0x3e, 0x07, 0x01, 0xbe, 0x09, 0x16, + 0x05, 0x25, 0x92, 0xc7, 0xf6, 0x26, 0xcc, 0x57, 0x17, 0x36, 0x56, 0x6c, 0xbd, 0xfa, 0x6a, 0x8d, + 0xa8, 0x94, 0x24, 0xcc, 0x2e, 0xc3, 0xfc, 0x6a, 0xdd, 0x4f, 0xcd, 0x38, 0xf3, 0x77, 0xb7, 0x4e, + 0xce, 0xdc, 0xda, 0x8b, 0x33, 0xb7, 0xf6, 0xf2, 0xcc, 0xad, 0x7d, 0x37, 0x76, 0x9d, 0x93, 0xb1, + 0xeb, 0xbc, 0x18, 0xbb, 0xce, 0xcb, 0xb1, 0xeb, 0xfc, 0x39, 0x76, 0x9d, 0x9f, 0xff, 0x72, 0x6b, + 0x5f, 0xd6, 0x47, 0x3b, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xad, 0x67, 0xe2, 0xf0, 0xc8, 0x0b, + 0x00, 0x00, +} + +func (m *AppliedManifestResourceMeta) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AppliedManifestResourceMeta) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AppliedManifestResourceMeta) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Namespace) + copy(dAtA[i:], m.Namespace) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Namespace))) + i-- + dAtA[i] = 0x2a + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x22 + i -= len(m.Resource) + copy(dAtA[i:], m.Resource) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Resource))) + i-- + dAtA[i] = 0x1a + i -= len(m.Version) + copy(dAtA[i:], m.Version) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Version))) + i-- + dAtA[i] = 0x12 + i -= len(m.Group) + copy(dAtA[i:], m.Group) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Group))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil } func (m *Manifest) Marshal() (dAtA []byte, err error) { @@ -712,6 +794,20 @@ func (m *ManifestWorkStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.AppliedResources) > 0 { + for iNdEx := len(m.AppliedResources) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.AppliedResources[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } { size, err := m.ResourceStatus.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -840,6 +936,25 @@ func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } +func (m *AppliedManifestResourceMeta) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Group) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Version) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Resource) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Namespace) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *Manifest) Size() (n int) { if m == nil { return 0 @@ -962,6 +1077,12 @@ func (m *ManifestWorkStatus) Size() (n int) { } l = m.ResourceStatus.Size() n += 1 + l + sovGenerated(uint64(l)) + if len(m.AppliedResources) > 0 { + for _, e := range m.AppliedResources { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } return n } @@ -1005,6 +1126,20 @@ func sovGenerated(x uint64) (n int) { func sozGenerated(x uint64) (n int) { return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } +func (this *AppliedManifestResourceMeta) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&AppliedManifestResourceMeta{`, + `Group:` + fmt.Sprintf("%v", this.Group) + `,`, + `Version:` + fmt.Sprintf("%v", this.Version) + `,`, + `Resource:` + fmt.Sprintf("%v", this.Resource) + `,`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `Namespace:` + fmt.Sprintf("%v", this.Namespace) + `,`, + `}`, + }, "") + return s +} func (this *Manifest) String() string { if this == nil { return "nil" @@ -1109,9 +1244,15 @@ func (this *ManifestWorkStatus) String() string { repeatedStringForConditions += strings.Replace(strings.Replace(f.String(), "StatusCondition", "StatusCondition", 1), `&`, ``, 1) + "," } repeatedStringForConditions += "}" + repeatedStringForAppliedResources := "[]AppliedManifestResourceMeta{" + for _, f := range this.AppliedResources { + repeatedStringForAppliedResources += strings.Replace(strings.Replace(f.String(), "AppliedManifestResourceMeta", "AppliedManifestResourceMeta", 1), `&`, ``, 1) + "," + } + repeatedStringForAppliedResources += "}" s := strings.Join([]string{`&ManifestWorkStatus{`, `Conditions:` + repeatedStringForConditions + `,`, `ResourceStatus:` + strings.Replace(strings.Replace(this.ResourceStatus.String(), "ManifestResourceStatus", "ManifestResourceStatus", 1), `&`, ``, 1) + `,`, + `AppliedResources:` + repeatedStringForAppliedResources + `,`, `}`, }, "") return s @@ -1153,6 +1294,219 @@ func valueToStringGenerated(v interface{}) string { pv := reflect.Indirect(rv).Interface() return fmt.Sprintf("*%v", pv) } +func (m *AppliedManifestResourceMeta) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AppliedManifestResourceMeta: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AppliedManifestResourceMeta: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Group", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Group = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Version = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Resource", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Resource = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Namespace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Namespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Manifest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -2164,6 +2518,40 @@ func (m *ManifestWorkStatus) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AppliedResources", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AppliedResources = append(m.AppliedResources, AppliedManifestResourceMeta{}) + if err := m.AppliedResources[len(m.AppliedResources)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/vendor/github.com/open-cluster-management/api/work/v1/generated.proto b/vendor/github.com/open-cluster-management/api/work/v1/generated.proto index 291b6528e..b4aa3eda9 100644 --- a/vendor/github.com/open-cluster-management/api/work/v1/generated.proto +++ b/vendor/github.com/open-cluster-management/api/work/v1/generated.proto @@ -12,6 +12,31 @@ import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto"; // Package-wide variables from generator "generated". option go_package = "v1"; +// AppliedManifestResourceMeta represents the gvr, name and namespace of a resource. +// Since these resources have been created, they must have valid group, version, resource, namespace, and name. +message AppliedManifestResourceMeta { + // Group is the API Group of the kubernetes resource + // +required + optional string group = 1; + + // Version is the version of the kubernetes resource + // +required + optional string version = 2; + + // Resource is the resource name of the kubernetes resource + // +required + optional string resource = 3; + + // Name is the name of the kubernetes resource + // +required + optional string name = 4; + + // Name is the namespace of the kubernetes resource, empty string indicates + // it is a cluster scoped resource. + // +required + optional string namespace = 5; +} + // Manifest represents a resource to be deployed on spoke cluster message Manifest { // +kubebuilder:validation:EmbeddedResource @@ -123,6 +148,15 @@ message ManifestWorkStatus { // spoke cluster. The agent on spoke cluster syncs the condition from spoke to the hub. // +optional optional ManifestResourceStatus resourceStatus = 2; + + // AppliedResources represents a list of resources defined within the manifestwork that are applied. + // Only resources with valid GroupVersionResource, namespace, and name are suitable. + // An item in this slice is deleted when there is no mapped manifest in manifestwork.Spec or by finalizer. + // The resource relating to the item will also be removed from spoke cluster. + // The deleted resource may still be present until the finalizers for that resource are finished. + // However, the resource will not be undeleted, so it can be removed from this list and eventual consistency is preserved. + // +optional + repeated AppliedManifestResourceMeta appliedResources = 3; } // ManifestsTemplate represents the manifest workload to be deployed on spoke cluster diff --git a/vendor/github.com/open-cluster-management/api/work/v1/types.go b/vendor/github.com/open-cluster-management/api/work/v1/types.go index 56600864e..81c988743 100644 --- a/vendor/github.com/open-cluster-management/api/work/v1/types.go +++ b/vendor/github.com/open-cluster-management/api/work/v1/types.go @@ -100,6 +100,31 @@ type ManifestResourceMeta struct { Namespace string `json:"namespace" protobuf:"bytes,7,opt,name=namespace"` } +// AppliedManifestResourceMeta represents the gvr, name and namespace of a resource. +// Since these resources have been created, they must have valid group, version, resource, namespace, and name. +type AppliedManifestResourceMeta struct { + // Group is the API Group of the kubernetes resource + // +required + Group string `json:"group" protobuf:"bytes,1,opt,name=group"` + + // Version is the version of the kubernetes resource + // +required + Version string `json:"version" protobuf:"bytes,2,opt,name=version"` + + // Resource is the resource name of the kubernetes resource + // +required + Resource string `json:"resource" protobuf:"bytes,3,opt,name=resource"` + + // Name is the name of the kubernetes resource + // +required + Name string `json:"name" protobuf:"bytes,4,opt,name=name"` + + // Name is the namespace of the kubernetes resource, empty string indicates + // it is a cluster scoped resource. + // +required + Namespace string `json:"namespace" protobuf:"bytes,5,opt,name=namespace"` +} + // ManifestWorkStatus represents the current status of spoke manifest workload type ManifestWorkStatus struct { // Conditions contains the different condition statuses for this work. @@ -115,6 +140,15 @@ type ManifestWorkStatus struct { // spoke cluster. The agent on spoke cluster syncs the condition from spoke to the hub. // +optional ResourceStatus ManifestResourceStatus `json:"resourceStatus,omitempty" protobuf:"bytes,2,rep,name=resourceStatus"` + + // AppliedResources represents a list of resources defined within the manifestwork that are applied. + // Only resources with valid GroupVersionResource, namespace, and name are suitable. + // An item in this slice is deleted when there is no mapped manifest in manifestwork.Spec or by finalizer. + // The resource relating to the item will also be removed from spoke cluster. + // The deleted resource may still be present until the finalizers for that resource are finished. + // However, the resource will not be undeleted, so it can be removed from this list and eventual consistency is preserved. + // +optional + AppliedResources []AppliedManifestResourceMeta `json:"appliedResources,omitempty" protobuf:"bytes,3,rep,name=appliedResources"` } // ManifestResourceStatus represents the status of each resource in manifest work deployed on diff --git a/vendor/github.com/open-cluster-management/api/work/v1/zz_generated.deepcopy.go b/vendor/github.com/open-cluster-management/api/work/v1/zz_generated.deepcopy.go index 6f3c62bcd..1307ab6eb 100644 --- a/vendor/github.com/open-cluster-management/api/work/v1/zz_generated.deepcopy.go +++ b/vendor/github.com/open-cluster-management/api/work/v1/zz_generated.deepcopy.go @@ -8,6 +8,22 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AppliedManifestResourceMeta) DeepCopyInto(out *AppliedManifestResourceMeta) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AppliedManifestResourceMeta. +func (in *AppliedManifestResourceMeta) DeepCopy() *AppliedManifestResourceMeta { + if in == nil { + return nil + } + out := new(AppliedManifestResourceMeta) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Manifest) DeepCopyInto(out *Manifest) { *out = *in @@ -177,6 +193,11 @@ func (in *ManifestWorkStatus) DeepCopyInto(out *ManifestWorkStatus) { } } in.ResourceStatus.DeepCopyInto(&out.ResourceStatus) + if in.AppliedResources != nil { + in, out := &in.AppliedResources, &out.AppliedResources + *out = make([]AppliedManifestResourceMeta, len(*in)) + copy(*out, *in) + } return } diff --git a/vendor/github.com/open-cluster-management/api/work/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/open-cluster-management/api/work/v1/zz_generated.swagger_doc_generated.go index bd13cc145..5201bada4 100644 --- a/vendor/github.com/open-cluster-management/api/work/v1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/open-cluster-management/api/work/v1/zz_generated.swagger_doc_generated.go @@ -11,6 +11,19 @@ package v1 // Those methods can be generated by using hack/update-swagger-docs.sh // AUTO-GENERATED FUNCTIONS START HERE +var map_AppliedManifestResourceMeta = map[string]string{ + "": "AppliedManifestResourceMeta represents the gvr, name and namespace of a resource. Since these resources have been created, they must have valid group, version, resource, namespace, and name.", + "group": "Group is the API Group of the kubernetes resource", + "version": "Version is the version of the kubernetes resource", + "resource": "Resource is the resource name of the kubernetes resource", + "name": "Name is the name of the kubernetes resource", + "namespace": "Name is the namespace of the kubernetes resource, empty string indicates it is a cluster scoped resource.", +} + +func (AppliedManifestResourceMeta) SwaggerDoc() map[string]string { + return map_AppliedManifestResourceMeta +} + var map_Manifest = map[string]string{ "": "Manifest represents a resource to be deployed on spoke cluster", } @@ -83,9 +96,10 @@ func (ManifestWorkSpec) SwaggerDoc() map[string]string { } var map_ManifestWorkStatus = map[string]string{ - "": "ManifestWorkStatus represents the current status of spoke manifest workload", - "conditions": "Conditions contains the different condition statuses for this work. Valid condition types are: 1. Applied represents workload in ManifestWork is applied successfully on spoke cluster. 2. Progressing represents workload in ManifestWork is being applied on spoke cluster. 3. Available represents workload in ManifestWork exists on the spoke cluster. 4. Degraded represents the current state of workload does not match the desired state for a certain period.", - "resourceStatus": "ResourceStatus represents the status of each resource in manifestwork deployed on spoke cluster. The agent on spoke cluster syncs the condition from spoke to the hub.", + "": "ManifestWorkStatus represents the current status of spoke manifest workload", + "conditions": "Conditions contains the different condition statuses for this work. Valid condition types are: 1. Applied represents workload in ManifestWork is applied successfully on spoke cluster. 2. Progressing represents workload in ManifestWork is being applied on spoke cluster. 3. Available represents workload in ManifestWork exists on the spoke cluster. 4. Degraded represents the current state of workload does not match the desired state for a certain period.", + "resourceStatus": "ResourceStatus represents the status of each resource in manifestwork deployed on spoke cluster. The agent on spoke cluster syncs the condition from spoke to the hub.", + "appliedResources": "AppliedResources represents a list of resources defined within the manifestwork that are applied. Only resources with valid GroupVersionResource, namespace, and name are suitable. An item in this slice is deleted when there is no mapped manifest in manifestwork.Spec or by finalizer. The resource relating to the item will also be removed from spoke cluster. The deleted resource may still be present until the finalizers for that resource are finished. However, the resource will not be undeleted, so it can be removed from this list and eventual consistency is preserved.", } func (ManifestWorkStatus) SwaggerDoc() map[string]string { diff --git a/vendor/k8s.io/utils/diff/diff.go b/vendor/k8s.io/utils/diff/diff.go new file mode 100644 index 000000000..2a6e3aebd --- /dev/null +++ b/vendor/k8s.io/utils/diff/diff.go @@ -0,0 +1,314 @@ +/* +Copyright 2014 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package diff + +import ( + "bytes" + "encoding/json" + "fmt" + "reflect" + "sort" + "strings" + "text/tabwriter" + + "github.com/davecgh/go-spew/spew" + + "k8s.io/utils/field" +) + +// StringDiff diffs a and b and returns a human readable diff. +func StringDiff(a, b string) string { + ba := []byte(a) + bb := []byte(b) + out := []byte{} + i := 0 + for ; i < len(ba) && i < len(bb); i++ { + if ba[i] != bb[i] { + break + } + out = append(out, ba[i]) + } + out = append(out, []byte("\n\nA: ")...) + out = append(out, ba[i:]...) + out = append(out, []byte("\n\nB: ")...) + out = append(out, bb[i:]...) + out = append(out, []byte("\n\n")...) + return string(out) +} + +// ObjectDiff writes the two objects out as JSON and prints out the identical part of +// the objects followed by the remaining part of 'a' and finally the remaining part of 'b'. +// For debugging tests. +func ObjectDiff(a, b interface{}) string { + ab, err := json.Marshal(a) + if err != nil { + panic(fmt.Sprintf("a: %v", err)) + } + bb, err := json.Marshal(b) + if err != nil { + panic(fmt.Sprintf("b: %v", err)) + } + return StringDiff(string(ab), string(bb)) +} + +// ObjectGoPrintDiff is like ObjectDiff, but uses go-spew to print the objects, +// which shows absolutely everything by recursing into every single pointer +// (go's %#v formatters OTOH stop at a certain point). This is needed when you +// can't figure out why reflect.DeepEqual is returning false and nothing is +// showing you differences. This will. +func ObjectGoPrintDiff(a, b interface{}) string { + s := spew.ConfigState{DisableMethods: true} + return StringDiff( + s.Sprintf("%#v", a), + s.Sprintf("%#v", b), + ) +} + +// ObjectReflectDiff returns a diff computed through reflection, without serializing to JSON. +func ObjectReflectDiff(a, b interface{}) string { + vA, vB := reflect.ValueOf(a), reflect.ValueOf(b) + if vA.Type() != vB.Type() { + return fmt.Sprintf("type A %T and type B %T do not match", a, b) + } + diffs := objectReflectDiff(field.NewPath("object"), vA, vB) + if len(diffs) == 0 { + return "" + } + out := []string{""} + for _, d := range diffs { + elidedA, elidedB := limit(d.a, d.b, 80) + out = append(out, + fmt.Sprintf("%s:", d.path), + fmt.Sprintf(" a: %s", elidedA), + fmt.Sprintf(" b: %s", elidedB), + ) + } + return strings.Join(out, "\n") +} + +// limit: +// 1. stringifies aObj and bObj +// 2. elides identical prefixes if either is too long +// 3. elides remaining content from the end if either is too long +func limit(aObj, bObj interface{}, max int) (string, string) { + elidedPrefix := "" + elidedASuffix := "" + elidedBSuffix := "" + a, b := fmt.Sprintf("%#v", aObj), fmt.Sprintf("%#v", bObj) + + if aObj != nil && bObj != nil { + if aType, bType := fmt.Sprintf("%T", aObj), fmt.Sprintf("%T", bObj); aType != bType { + a = fmt.Sprintf("%s (%s)", a, aType) + b = fmt.Sprintf("%s (%s)", b, bType) + } + } + + for { + switch { + case len(a) > max && len(a) > 4 && len(b) > 4 && a[:4] == b[:4]: + // a is too long, b has data, and the first several characters are the same + elidedPrefix = "..." + a = a[2:] + b = b[2:] + + case len(b) > max && len(b) > 4 && len(a) > 4 && a[:4] == b[:4]: + // b is too long, a has data, and the first several characters are the same + elidedPrefix = "..." + a = a[2:] + b = b[2:] + + case len(a) > max: + a = a[:max] + elidedASuffix = "..." + + case len(b) > max: + b = b[:max] + elidedBSuffix = "..." + + default: + // both are short enough + return elidedPrefix + a + elidedASuffix, elidedPrefix + b + elidedBSuffix + } + } +} + +func public(s string) bool { + if len(s) == 0 { + return false + } + return s[:1] == strings.ToUpper(s[:1]) +} + +type diff struct { + path *field.Path + a, b interface{} +} + +type orderedDiffs []diff + +func (d orderedDiffs) Len() int { return len(d) } +func (d orderedDiffs) Swap(i, j int) { d[i], d[j] = d[j], d[i] } +func (d orderedDiffs) Less(i, j int) bool { + a, b := d[i].path.String(), d[j].path.String() + if a < b { + return true + } + return false +} + +func objectReflectDiff(path *field.Path, a, b reflect.Value) []diff { + switch a.Type().Kind() { + case reflect.Struct: + var changes []diff + for i := 0; i < a.Type().NumField(); i++ { + if !public(a.Type().Field(i).Name) { + if reflect.DeepEqual(a.Interface(), b.Interface()) { + continue + } + return []diff{{path: path, a: fmt.Sprintf("%#v", a), b: fmt.Sprintf("%#v", b)}} + } + if sub := objectReflectDiff(path.Child(a.Type().Field(i).Name), a.Field(i), b.Field(i)); len(sub) > 0 { + changes = append(changes, sub...) + } + } + return changes + case reflect.Ptr, reflect.Interface: + if a.IsNil() || b.IsNil() { + switch { + case a.IsNil() && b.IsNil(): + return nil + case a.IsNil(): + return []diff{{path: path, a: nil, b: b.Interface()}} + default: + return []diff{{path: path, a: a.Interface(), b: nil}} + } + } + return objectReflectDiff(path, a.Elem(), b.Elem()) + case reflect.Chan: + if !reflect.DeepEqual(a.Interface(), b.Interface()) { + return []diff{{path: path, a: a.Interface(), b: b.Interface()}} + } + return nil + case reflect.Slice: + lA, lB := a.Len(), b.Len() + l := lA + if lB < lA { + l = lB + } + if lA == lB && lA == 0 { + if a.IsNil() != b.IsNil() { + return []diff{{path: path, a: a.Interface(), b: b.Interface()}} + } + return nil + } + var diffs []diff + for i := 0; i < l; i++ { + if !reflect.DeepEqual(a.Index(i), b.Index(i)) { + diffs = append(diffs, objectReflectDiff(path.Index(i), a.Index(i), b.Index(i))...) + } + } + for i := l; i < lA; i++ { + diffs = append(diffs, diff{path: path.Index(i), a: a.Index(i), b: nil}) + } + for i := l; i < lB; i++ { + diffs = append(diffs, diff{path: path.Index(i), a: nil, b: b.Index(i)}) + } + return diffs + case reflect.Map: + if reflect.DeepEqual(a.Interface(), b.Interface()) { + return nil + } + aKeys := make(map[interface{}]interface{}) + for _, key := range a.MapKeys() { + aKeys[key.Interface()] = a.MapIndex(key).Interface() + } + var missing []diff + for _, key := range b.MapKeys() { + if _, ok := aKeys[key.Interface()]; ok { + delete(aKeys, key.Interface()) + if reflect.DeepEqual(a.MapIndex(key).Interface(), b.MapIndex(key).Interface()) { + continue + } + missing = append(missing, objectReflectDiff(path.Key(fmt.Sprintf("%s", key.Interface())), a.MapIndex(key), b.MapIndex(key))...) + continue + } + missing = append(missing, diff{path: path.Key(fmt.Sprintf("%s", key.Interface())), a: nil, b: b.MapIndex(key).Interface()}) + } + for key, value := range aKeys { + missing = append(missing, diff{path: path.Key(fmt.Sprintf("%s", key)), a: value, b: nil}) + } + if len(missing) == 0 { + missing = append(missing, diff{path: path, a: a.Interface(), b: b.Interface()}) + } + sort.Sort(orderedDiffs(missing)) + return missing + default: + if reflect.DeepEqual(a.Interface(), b.Interface()) { + return nil + } + if !a.CanInterface() { + return []diff{{path: path, a: fmt.Sprintf("%#v", a), b: fmt.Sprintf("%#v", b)}} + } + return []diff{{path: path, a: a.Interface(), b: b.Interface()}} + } +} + +// ObjectGoPrintSideBySide prints a and b as textual dumps side by side, +// enabling easy visual scanning for mismatches. +func ObjectGoPrintSideBySide(a, b interface{}) string { + s := spew.ConfigState{ + Indent: " ", + // Extra deep spew. + DisableMethods: true, + } + sA := s.Sdump(a) + sB := s.Sdump(b) + + linesA := strings.Split(sA, "\n") + linesB := strings.Split(sB, "\n") + width := 0 + for _, s := range linesA { + l := len(s) + if l > width { + width = l + } + } + for _, s := range linesB { + l := len(s) + if l > width { + width = l + } + } + buf := &bytes.Buffer{} + w := tabwriter.NewWriter(buf, width, 0, 1, ' ', 0) + max := len(linesA) + if len(linesB) > max { + max = len(linesB) + } + for i := 0; i < max; i++ { + var a, b string + if i < len(linesA) { + a = linesA[i] + } + if i < len(linesB) { + b = linesB[i] + } + fmt.Fprintf(w, "%s\t%s\n", a, b) + } + w.Flush() + return buf.String() +} diff --git a/vendor/k8s.io/utils/field/path.go b/vendor/k8s.io/utils/field/path.go new file mode 100644 index 000000000..2efc8eec7 --- /dev/null +++ b/vendor/k8s.io/utils/field/path.go @@ -0,0 +1,91 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package field + +import ( + "bytes" + "fmt" + "strconv" +) + +// Path represents the path from some root to a particular field. +type Path struct { + name string // the name of this field or "" if this is an index + index string // if name == "", this is a subscript (index or map key) of the previous element + parent *Path // nil if this is the root element +} + +// NewPath creates a root Path object. +func NewPath(name string, moreNames ...string) *Path { + r := &Path{name: name, parent: nil} + for _, anotherName := range moreNames { + r = &Path{name: anotherName, parent: r} + } + return r +} + +// Root returns the root element of this Path. +func (p *Path) Root() *Path { + for ; p.parent != nil; p = p.parent { + // Do nothing. + } + return p +} + +// Child creates a new Path that is a child of the method receiver. +func (p *Path) Child(name string, moreNames ...string) *Path { + r := NewPath(name, moreNames...) + r.Root().parent = p + return r +} + +// Index indicates that the previous Path is to be subscripted by an int. +// This sets the same underlying value as Key. +func (p *Path) Index(index int) *Path { + return &Path{index: strconv.Itoa(index), parent: p} +} + +// Key indicates that the previous Path is to be subscripted by a string. +// This sets the same underlying value as Index. +func (p *Path) Key(key string) *Path { + return &Path{index: key, parent: p} +} + +// String produces a string representation of the Path. +func (p *Path) String() string { + // make a slice to iterate + elems := []*Path{} + for ; p != nil; p = p.parent { + elems = append(elems, p) + } + + // iterate, but it has to be backwards + buf := bytes.NewBuffer(nil) + for i := range elems { + p := elems[len(elems)-1-i] + if p.parent != nil && len(p.name) > 0 { + // This is either the root or it is a subscript. + buf.WriteString(".") + } + if len(p.name) > 0 { + buf.WriteString(p.name) + } else { + fmt.Fprintf(buf, "[%s]", p.index) + } + } + return buf.String() +} diff --git a/vendor/modules.txt b/vendor/modules.txt index a810f6d60..a480f9bd2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -130,7 +130,7 @@ github.com/onsi/gomega/matchers/support/goraph/edge github.com/onsi/gomega/matchers/support/goraph/node github.com/onsi/gomega/matchers/support/goraph/util github.com/onsi/gomega/types -# github.com/open-cluster-management/api v0.0.0-20200512175145-bed9ce79e17e +# github.com/open-cluster-management/api v0.0.0-20200528225735-c85cec6fa5b0 github.com/open-cluster-management/api/client/work/clientset/versioned github.com/open-cluster-management/api/client/work/clientset/versioned/fake github.com/open-cluster-management/api/client/work/clientset/versioned/scheme @@ -853,6 +853,8 @@ k8s.io/kube-openapi/pkg/util/proto k8s.io/kubectl/pkg/scheme # k8s.io/utils v0.0.0-20200327001022-6496210b90e8 k8s.io/utils/buffer +k8s.io/utils/diff +k8s.io/utils/field k8s.io/utils/integer k8s.io/utils/net k8s.io/utils/path