From bb84f24cb0d86c3feebb89ef522f9a406a56fb8b Mon Sep 17 00:00:00 2001 From: Karl Isenberg Date: Mon, 14 Feb 2022 22:35:53 -0800 Subject: [PATCH] chore: Move Inventory object to pkg/apis/actuation - Replace custom TypeMeta & ObjectMeta with standard metav1 structs to allow Inventory to satisfy the metav1.Object, runtime.Object, and client.Object interfaces. This should make the Inventory API easier to use and easily convertable to an Unstructured object. BREAKING CHANGE: Move inventory.Inventory to actuation.Inventory (under pkg/apis/) --- LICENSE_TEMPLATE_GO | 2 + Makefile | 8 +- hack/run-in-gopath.sh | 43 ++++ .../actuation}/actuationstatus_string.go | 2 +- .../actuation}/actuationstrategy_string.go | 2 +- pkg/apis/actuation/doc.go | 8 + .../actuation}/reconcilestatus_string.go | 2 +- pkg/{inventory => apis/actuation}/types.go | 39 +--- pkg/apis/actuation/zz_generated.deepcopy.go | 104 +++++++++ pkg/apply/taskrunner/task_test.go | 209 +++++++++--------- pkg/inventory/manager.go | 143 ++++++------ pkg/inventory/type-conv.go | 9 +- 12 files changed, 357 insertions(+), 214 deletions(-) create mode 100644 LICENSE_TEMPLATE_GO create mode 100755 hack/run-in-gopath.sh rename pkg/{inventory => apis/actuation}/actuationstatus_string.go (97%) rename pkg/{inventory => apis/actuation}/actuationstrategy_string.go (97%) create mode 100644 pkg/apis/actuation/doc.go rename pkg/{inventory => apis/actuation}/reconcilestatus_string.go (97%) rename pkg/{inventory => apis/actuation}/types.go (70%) create mode 100644 pkg/apis/actuation/zz_generated.deepcopy.go diff --git a/LICENSE_TEMPLATE_GO b/LICENSE_TEMPLATE_GO new file mode 100644 index 00000000..ef790b66 --- /dev/null +++ b/LICENSE_TEMPLATE_GO @@ -0,0 +1,2 @@ +// Copyright YEAR The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 diff --git a/Makefile b/Makefile index bc7edb57..b992268d 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,13 @@ install-addlicense: install-lint: (which $(GOPATH)/bin/golangci-lint || go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.40.1) -generate: install-stringer +install-deepcopy-gen: + (which $(GOPATH)/bin/deepcopy-gen || go install k8s.io/code-generator/cmd/deepcopy-gen@v0.23.3) + +generate-deepcopy: install-deepcopy-gen + hack/run-in-gopath.sh deepcopy-gen --input-dirs ./pkg/apis/... -O zz_generated.deepcopy --go-header-file ./LICENSE_TEMPLATE_GO + +generate: install-stringer generate-deepcopy go generate ./... license: install-addlicense diff --git a/hack/run-in-gopath.sh b/hack/run-in-gopath.sh new file mode 100755 index 00000000..1a4983d8 --- /dev/null +++ b/hack/run-in-gopath.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Copyright 2021 The Kubernetes Authors. +# SPDX-License-Identifier: Apache-2.0 + +set -o errexit -o nounset -o pipefail -o posix + +PKG_PATH="sigs.k8s.io/cli-utils" + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" + +# Make a new temporary GOPATH directory +export GOPATH=$(mktemp -d -t cli-utils-gopath.XXXXXXXXXX) +# Clean up on exit (modcache has read-only files, so clean that first) +trap "go clean -modcache && rm '${GOPATH}/src/${PKG_PATH}' && rm -rf '${GOPATH}'" EXIT + +# Make sure we can read, write, and delete +chmod a+rw "${GOPATH}" + +# Use a temporary cache +export GOCACHE="${GOPATH}/cache" + +# Create a symlink for the local repo in the GOPATH +mkdir -p "${GOPATH}/src/${PKG_PATH}" +rm -r "${GOPATH}/src/${PKG_PATH}" +ln -s "${REPO_ROOT}" "${GOPATH}/src/${PKG_PATH}" + +# Make sure our own Go binaries are in PATH. +export PATH="${GOPATH}/bin:${PATH}" + +# Set GOROOT so binaries that parse code can work properly. +export GOROOT=$(go env GOROOT) + +# Unset GOBIN in case it already exists in the current session. +unset GOBIN + +# enter the GOPATH before executing the command +cd "${GOPATH}/src/${PKG_PATH}" + +# Run the user-provided command. +"${@}" + +# exit the GOPATH before deleting it +cd "${REPO_ROOT}" diff --git a/pkg/inventory/actuationstatus_string.go b/pkg/apis/actuation/actuationstatus_string.go similarity index 97% rename from pkg/inventory/actuationstatus_string.go rename to pkg/apis/actuation/actuationstatus_string.go index e9327790..7725bef8 100644 --- a/pkg/inventory/actuationstatus_string.go +++ b/pkg/apis/actuation/actuationstatus_string.go @@ -1,6 +1,6 @@ // Code generated by "stringer -type=ActuationStatus -linecomment"; DO NOT EDIT. -package inventory +package actuation import "strconv" diff --git a/pkg/inventory/actuationstrategy_string.go b/pkg/apis/actuation/actuationstrategy_string.go similarity index 97% rename from pkg/inventory/actuationstrategy_string.go rename to pkg/apis/actuation/actuationstrategy_string.go index b20f67fd..73e8aef3 100644 --- a/pkg/inventory/actuationstrategy_string.go +++ b/pkg/apis/actuation/actuationstrategy_string.go @@ -1,6 +1,6 @@ // Code generated by "stringer -type=ActuationStrategy -linecomment"; DO NOT EDIT. -package inventory +package actuation import "strconv" diff --git a/pkg/apis/actuation/doc.go b/pkg/apis/actuation/doc.go new file mode 100644 index 00000000..bf515ce8 --- /dev/null +++ b/pkg/apis/actuation/doc.go @@ -0,0 +1,8 @@ +// Copyright 2021 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +// Package actuation contains API Schema definitions for the +// cli-utils.kubernetes.io API group. +// +k8s:deepcopy-gen=package +// +groupName=cli-utils.kubernetes.io +package actuation // import "sigs.k8s.io/cli-utils/pkg/apis/actuation" diff --git a/pkg/inventory/reconcilestatus_string.go b/pkg/apis/actuation/reconcilestatus_string.go similarity index 97% rename from pkg/inventory/reconcilestatus_string.go rename to pkg/apis/actuation/reconcilestatus_string.go index d40d39c8..0237cc9b 100644 --- a/pkg/inventory/reconcilestatus_string.go +++ b/pkg/apis/actuation/reconcilestatus_string.go @@ -1,6 +1,6 @@ // Code generated by "stringer -type=ReconcileStatus -linecomment"; DO NOT EDIT. -package inventory +package actuation import "strconv" diff --git a/pkg/inventory/types.go b/pkg/apis/actuation/types.go similarity index 70% rename from pkg/inventory/types.go rename to pkg/apis/actuation/types.go index 0e99f833..49cbdfb0 100644 --- a/pkg/inventory/types.go +++ b/pkg/apis/actuation/types.go @@ -1,18 +1,19 @@ // Copyright 2021 The Kubernetes Authors. // SPDX-License-Identifier: Apache-2.0 -package inventory +package actuation -import "k8s.io/apimachinery/pkg/types" +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) // Inventory represents the inventory object in memory. // Inventory is currently only used for in-memory storage and not serialized to // disk or to the API server. -// TODO: Replace InventoryInfo with Inventory.TypeMeta & Inventory.ObjectMeta -// TODO: Replace object.ObjMetadataSet in Storage interface with Inventory.Spec type Inventory struct { - TypeMeta `json:",inline"` - ObjectMeta `json:"metadata,omitempty"` + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` Spec InventorySpec `json:"spec,omitempty"` Status InventoryStatus `json:"status,omitempty"` @@ -106,29 +107,3 @@ const ( ReconcileFailed // Failed ReconcileTimeout // Timeout ) - -// TypeMeta describes a REST resource. -type TypeMeta struct { - // Kind is a string value representing the REST resource this object represents. - // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds - Kind string `json:"kind,omitempty"` - - // APIVersion defines the versioned schema of this representation of an object. - // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources - APIVersion string `json:"apiVersion,omitempty"` -} - -// ObjectMeta describes an individual object instance of a REST resource. -// TODO: Do we need other fields, like UID, Generation, ResourceVersion, and CreationTimestamp? -type ObjectMeta struct { - // Name identifies an object instance of a REST resource. - // More info: http://kubernetes.io/docs/user-guide/identifiers#names - Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"` - - // Namespace identifies a group of objects across REST resources. - // If namespace is specified, the resource must be namespace-scoped. - // If namespace is omitted, the resource must be cluster-scoped. - // More info: http://kubernetes.io/docs/user-guide/namespaces - // +optional - Namespace string `json:"namespace,omitempty" protobuf:"bytes,3,opt,name=namespace"` -} diff --git a/pkg/apis/actuation/zz_generated.deepcopy.go b/pkg/apis/actuation/zz_generated.deepcopy.go new file mode 100644 index 00000000..90f63840 --- /dev/null +++ b/pkg/apis/actuation/zz_generated.deepcopy.go @@ -0,0 +1,104 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// Copyright 2022 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package actuation + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Inventory) DeepCopyInto(out *Inventory) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Inventory. +func (in *Inventory) DeepCopy() *Inventory { + if in == nil { + return nil + } + out := new(Inventory) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InventorySpec) DeepCopyInto(out *InventorySpec) { + *out = *in + if in.Objects != nil { + in, out := &in.Objects, &out.Objects + *out = make([]ObjectReference, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InventorySpec. +func (in *InventorySpec) DeepCopy() *InventorySpec { + if in == nil { + return nil + } + out := new(InventorySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InventoryStatus) DeepCopyInto(out *InventoryStatus) { + *out = *in + if in.Objects != nil { + in, out := &in.Objects, &out.Objects + *out = make([]ObjectStatus, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InventoryStatus. +func (in *InventoryStatus) DeepCopy() *InventoryStatus { + if in == nil { + return nil + } + out := new(InventoryStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ObjectReference) DeepCopyInto(out *ObjectReference) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectReference. +func (in *ObjectReference) DeepCopy() *ObjectReference { + if in == nil { + return nil + } + out := new(ObjectReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ObjectStatus) DeepCopyInto(out *ObjectStatus) { + *out = *in + out.ObjectReference = in.ObjectReference + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectStatus. +func (in *ObjectStatus) DeepCopy() *ObjectStatus { + if in == nil { + return nil + } + out := new(ObjectStatus) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/apply/taskrunner/task_test.go b/pkg/apply/taskrunner/task_test.go index bfcbb29b..97f2fbdc 100644 --- a/pkg/apply/taskrunner/task_test.go +++ b/pkg/apply/taskrunner/task_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "sigs.k8s.io/cli-utils/pkg/apis/actuation" "sigs.k8s.io/cli-utils/pkg/apply/cache" "sigs.k8s.io/cli-utils/pkg/apply/event" "sigs.k8s.io/cli-utils/pkg/inventory" @@ -215,36 +216,36 @@ loop: "Actual events (%d) do not match expected events (%d)", len(receivedEvents), len(expectedEvents)) - expectedInventory := inventory.Inventory{ - Status: inventory.InventoryStatus{ - Objects: []inventory.ObjectStatus{ + expectedInventory := actuation.Inventory{ + Status: actuation.InventoryStatus{ + Objects: []actuation.ObjectStatus{ { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment1ID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSucceeded, - Reconcile: inventory.ReconcileSucceeded, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcileSucceeded, UID: testDeployment1.GetUID(), Generation: testDeployment1.GetGeneration(), }, { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment2ID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSucceeded, - Reconcile: inventory.ReconcileSucceeded, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcileSucceeded, UID: testDeployment2.GetUID(), Generation: testDeployment2.GetGeneration(), }, { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment3ID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationFailed, - Reconcile: inventory.ReconcileSkipped, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationFailed, + Reconcile: actuation.ReconcileSkipped, }, { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment4ID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSkipped, - Reconcile: inventory.ReconcileSkipped, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSkipped, + Reconcile: actuation.ReconcileSkipped, }, }, }, @@ -387,36 +388,36 @@ loop: "Actual events (%d) do not match expected events (%d)", len(receivedEvents), len(expectedEvents)) - expectedInventory := inventory.Inventory{ - Status: inventory.InventoryStatus{ - Objects: []inventory.ObjectStatus{ + expectedInventory := actuation.Inventory{ + Status: actuation.InventoryStatus{ + Objects: []actuation.ObjectStatus{ { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment1ID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSucceeded, - Reconcile: inventory.ReconcileSucceeded, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcileSucceeded, UID: testDeployment1.GetUID(), Generation: testDeployment1.GetGeneration(), }, { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment2ID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSucceeded, - Reconcile: inventory.ReconcileTimeout, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcileTimeout, UID: testDeployment2.GetUID(), Generation: testDeployment2.GetGeneration(), }, { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment3ID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationFailed, - Reconcile: inventory.ReconcileSkipped, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationFailed, + Reconcile: actuation.ReconcileSkipped, }, { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment4ID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSkipped, - Reconcile: inventory.ReconcileSkipped, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSkipped, + Reconcile: actuation.ReconcileSkipped, }, }, }, @@ -492,14 +493,14 @@ loop: "Actual events (%d) do not match expected events (%d)", len(receivedEvents), len(expectedEvents)) - expectedInventory := inventory.Inventory{ - Status: inventory.InventoryStatus{ - Objects: []inventory.ObjectStatus{ + expectedInventory := actuation.Inventory{ + Status: actuation.InventoryStatus{ + Objects: []actuation.ObjectStatus{ { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeploymentID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSucceeded, - Reconcile: inventory.ReconcileSucceeded, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcileSucceeded, UID: testDeployment.GetUID(), Generation: testDeployment.GetGeneration(), }, @@ -579,14 +580,14 @@ loop: "Actual events (%d) do not match expected events (%d)", len(receivedEvents), len(expectedEvents)) - expectedInventory := inventory.Inventory{ - Status: inventory.InventoryStatus{ - Objects: []inventory.ObjectStatus{ + expectedInventory := actuation.Inventory{ + Status: actuation.InventoryStatus{ + Objects: []actuation.ObjectStatus{ { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeploymentID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSucceeded, - Reconcile: inventory.ReconcilePending, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcilePending, UID: testDeployment.GetUID(), Generation: testDeployment.GetGeneration(), }, @@ -687,14 +688,14 @@ loop: } assert.Equal(t, expectedResults, receivedResults) - expectedInventory := inventory.Inventory{ - Status: inventory.InventoryStatus{ - Objects: []inventory.ObjectStatus{ + expectedInventory := actuation.Inventory{ + Status: actuation.InventoryStatus{ + Objects: []actuation.ObjectStatus{ { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeploymentID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSucceeded, - Reconcile: inventory.ReconcileSucceeded, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcileSucceeded, UID: testDeployment.GetUID(), Generation: testDeployment.GetGeneration(), }, @@ -722,7 +723,7 @@ func TestWaitTask_Failed(t *testing.T) { eventsFunc func(*cache.ResourceCacheMap, *WaitTask, *TaskContext) waitTimeout time.Duration expectedEvents []event.Event - expectedInventory *inventory.Inventory + expectedInventory *actuation.Inventory }{ "continue on failed if others InProgress": { configureTaskContextFunc: func(taskContext *TaskContext) { @@ -790,22 +791,22 @@ func TestWaitTask_Failed(t *testing.T) { }, }, }, - expectedInventory: &inventory.Inventory{ - Status: inventory.InventoryStatus{ - Objects: []inventory.ObjectStatus{ + expectedInventory: &actuation.Inventory{ + Status: actuation.InventoryStatus{ + Objects: []actuation.ObjectStatus{ { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment1ID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSucceeded, - Reconcile: inventory.ReconcileFailed, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcileFailed, UID: testDeployment1.GetUID(), Generation: testDeployment1.GetGeneration(), }, { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment2ID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSucceeded, - Reconcile: inventory.ReconcileSucceeded, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcileSucceeded, UID: testDeployment2.GetUID(), Generation: testDeployment2.GetGeneration(), }, @@ -873,22 +874,22 @@ func TestWaitTask_Failed(t *testing.T) { }, }, }, - expectedInventory: &inventory.Inventory{ - Status: inventory.InventoryStatus{ - Objects: []inventory.ObjectStatus{ + expectedInventory: &actuation.Inventory{ + Status: actuation.InventoryStatus{ + Objects: []actuation.ObjectStatus{ { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment1ID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSucceeded, - Reconcile: inventory.ReconcileFailed, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcileFailed, UID: testDeployment1.GetUID(), Generation: testDeployment1.GetGeneration(), }, { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment2ID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSucceeded, - Reconcile: inventory.ReconcileSucceeded, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcileSucceeded, UID: testDeployment2.GetUID(), Generation: testDeployment2.GetGeneration(), }, @@ -971,22 +972,22 @@ func TestWaitTask_Failed(t *testing.T) { }, }, }, - expectedInventory: &inventory.Inventory{ - Status: inventory.InventoryStatus{ - Objects: []inventory.ObjectStatus{ + expectedInventory: &actuation.Inventory{ + Status: actuation.InventoryStatus{ + Objects: []actuation.ObjectStatus{ { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment1ID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSucceeded, - Reconcile: inventory.ReconcileSucceeded, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcileSucceeded, UID: testDeployment1.GetUID(), Generation: testDeployment1.GetGeneration(), }, { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment2ID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSucceeded, - Reconcile: inventory.ReconcileSucceeded, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcileSucceeded, UID: testDeployment2.GetUID(), Generation: testDeployment2.GetGeneration(), }, @@ -1078,22 +1079,22 @@ func TestWaitTask_Failed(t *testing.T) { }, }, }, - expectedInventory: &inventory.Inventory{ - Status: inventory.InventoryStatus{ - Objects: []inventory.ObjectStatus{ + expectedInventory: &actuation.Inventory{ + Status: actuation.InventoryStatus{ + Objects: []actuation.ObjectStatus{ { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment1ID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSucceeded, - Reconcile: inventory.ReconcileTimeout, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcileTimeout, UID: testDeployment1.GetUID(), Generation: testDeployment1.GetGeneration(), }, { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment2ID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSucceeded, - Reconcile: inventory.ReconcileSucceeded, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcileSucceeded, UID: testDeployment2.GetUID(), Generation: testDeployment2.GetGeneration(), }, @@ -1175,7 +1176,7 @@ func TestWaitTask_UIDChanged(t *testing.T) { eventsFunc func(*cache.ResourceCacheMap, *WaitTask, *TaskContext) waitTimeout time.Duration expectedEvents []event.Event - expectedInventory *inventory.Inventory + expectedInventory *actuation.Inventory }{ "UID changed after apply means reconcile failure": { condition: AllCurrent, @@ -1239,24 +1240,24 @@ func TestWaitTask_UIDChanged(t *testing.T) { }, }, }, - expectedInventory: &inventory.Inventory{ - Status: inventory.InventoryStatus{ - Objects: []inventory.ObjectStatus{ + expectedInventory: &actuation.Inventory{ + Status: actuation.InventoryStatus{ + Objects: []actuation.ObjectStatus{ { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment1ID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSucceeded, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSucceeded, // UID change causes failure after apply - Reconcile: inventory.ReconcileFailed, + Reconcile: actuation.ReconcileFailed, // Recorded UID should be from the applied object, not the new replacement UID: testDeployment1.GetUID(), Generation: testDeployment1.GetGeneration(), }, { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment2ID), - Strategy: inventory.ActuationStrategyApply, - Actuation: inventory.ActuationSucceeded, - Reconcile: inventory.ReconcileSucceeded, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcileSucceeded, UID: testDeployment2.GetUID(), Generation: testDeployment2.GetGeneration(), }, @@ -1326,24 +1327,24 @@ func TestWaitTask_UIDChanged(t *testing.T) { }, }, }, - expectedInventory: &inventory.Inventory{ - Status: inventory.InventoryStatus{ - Objects: []inventory.ObjectStatus{ + expectedInventory: &actuation.Inventory{ + Status: actuation.InventoryStatus{ + Objects: []actuation.ObjectStatus{ { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment1ID), - Strategy: inventory.ActuationStrategyDelete, - Actuation: inventory.ActuationSucceeded, + Strategy: actuation.ActuationStrategyDelete, + Actuation: actuation.ActuationSucceeded, // UID change causes success after delete - Reconcile: inventory.ReconcileSucceeded, + Reconcile: actuation.ReconcileSucceeded, // Recorded UID should be from the deleted object, not the new replacement UID: testDeployment1.GetUID(), // Deleted generation is unknown }, { ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment2ID), - Strategy: inventory.ActuationStrategyDelete, - Actuation: inventory.ActuationSucceeded, - Reconcile: inventory.ReconcileSucceeded, + Strategy: actuation.ActuationStrategyDelete, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcileSucceeded, UID: testDeployment2.GetUID(), // Deleted generation is unknown }, diff --git a/pkg/inventory/manager.go b/pkg/inventory/manager.go index 9fbd0806..abbe0f7e 100644 --- a/pkg/inventory/manager.go +++ b/pkg/inventory/manager.go @@ -8,29 +8,30 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" + "sigs.k8s.io/cli-utils/pkg/apis/actuation" "sigs.k8s.io/cli-utils/pkg/object" ) // Manager wraps an Inventory with convenience methods that use ObjMetadata. type Manager struct { - inventory *Inventory + inventory *actuation.Inventory } // NewManager returns a new manager instance. func NewManager() *Manager { return &Manager{ - inventory: &Inventory{}, + inventory: &actuation.Inventory{}, } } // Inventory returns the in-memory version of the managed inventory. -func (tc *Manager) Inventory() *Inventory { +func (tc *Manager) Inventory() *actuation.Inventory { return tc.inventory } // ObjectStatus retrieves the status of an object with the specified ID. // The returned status is a pointer and can be updated in-place for efficiency. -func (tc *Manager) ObjectStatus(id object.ObjMetadata) (*ObjectStatus, bool) { +func (tc *Manager) ObjectStatus(id object.ObjMetadata) (*actuation.ObjectStatus, bool) { for i, objStatus := range tc.inventory.Status.Objects { if ObjMetadataEqualObjectReference(id, objStatus.ObjectReference) { return &(tc.inventory.Status.Objects[i]), true @@ -41,7 +42,7 @@ func (tc *Manager) ObjectStatus(id object.ObjMetadata) (*ObjectStatus, bool) { // ObjectsWithActuationStatus retrieves the set of objects with the // specified actuation strategy and status. -func (tc *Manager) ObjectsWithActuationStatus(strategy ActuationStrategy, status ActuationStatus) object.ObjMetadataSet { +func (tc *Manager) ObjectsWithActuationStatus(strategy actuation.ActuationStrategy, status actuation.ActuationStatus) object.ObjMetadataSet { var ids object.ObjMetadataSet for _, objStatus := range tc.inventory.Status.Objects { if objStatus.Strategy == strategy && objStatus.Actuation == status { @@ -53,7 +54,7 @@ func (tc *Manager) ObjectsWithActuationStatus(strategy ActuationStrategy, status // ObjectsWithActuationStatus retrieves the set of objects with the // specified reconcile status, regardless of actuation strategy. -func (tc *Manager) ObjectsWithReconcileStatus(status ReconcileStatus) object.ObjMetadataSet { +func (tc *Manager) ObjectsWithReconcileStatus(status actuation.ReconcileStatus) object.ObjMetadataSet { var ids object.ObjMetadataSet for _, objStatus := range tc.inventory.Status.Objects { if objStatus.Reconcile == status { @@ -64,7 +65,7 @@ func (tc *Manager) ObjectsWithReconcileStatus(status ReconcileStatus) object.Obj } // SetObjectStatus updates or adds an ObjectStatus record to the inventory. -func (tc *Manager) SetObjectStatus(id object.ObjMetadata, objStatus ObjectStatus) { +func (tc *Manager) SetObjectStatus(id object.ObjMetadata, objStatus actuation.ObjectStatus) { for i, objStatus := range tc.inventory.Status.Objects { if ObjMetadataEqualObjectReference(id, objStatus.ObjectReference) { tc.inventory.Status.Objects[i] = objStatus @@ -80,19 +81,19 @@ func (tc *Manager) IsSuccessfulApply(id object.ObjMetadata) bool { if !found { return false } - return objStatus.Strategy == ActuationStrategyApply && - objStatus.Actuation == ActuationSucceeded + return objStatus.Strategy == actuation.ActuationStrategyApply && + objStatus.Actuation == actuation.ActuationSucceeded } // AddSuccessfulApply updates the context with information about the // resource identified by the provided id. Currently, we keep information // about the generation of the resource after the apply operation completed. func (tc *Manager) AddSuccessfulApply(id object.ObjMetadata, uid types.UID, gen int64) { - tc.SetObjectStatus(id, ObjectStatus{ + tc.SetObjectStatus(id, actuation.ObjectStatus{ ObjectReference: ObjectReferenceFromObjMetadata(id), - Strategy: ActuationStrategyApply, - Actuation: ActuationSucceeded, - Reconcile: ReconcilePending, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcilePending, UID: uid, Generation: gen, }) @@ -101,16 +102,16 @@ func (tc *Manager) AddSuccessfulApply(id object.ObjMetadata, uid types.UID, gen // SuccessfulApplies returns all the objects (as ObjMetadata) that // were added as applied resources to the Manager. func (tc *Manager) SuccessfulApplies() object.ObjMetadataSet { - return tc.ObjectsWithActuationStatus(ActuationStrategyApply, - ActuationSucceeded) + return tc.ObjectsWithActuationStatus(actuation.ActuationStrategyApply, + actuation.ActuationSucceeded) } // AppliedResourceUID looks up the UID of a successfully applied resource func (tc *Manager) AppliedResourceUID(id object.ObjMetadata) (types.UID, bool) { objStatus, found := tc.ObjectStatus(id) return objStatus.UID, found && - objStatus.Strategy == ActuationStrategyApply && - objStatus.Actuation == ActuationSucceeded + objStatus.Strategy == actuation.ActuationStrategyApply && + objStatus.Actuation == actuation.ActuationSucceeded } // AppliedResourceUIDs returns a set with the UIDs of all the @@ -118,8 +119,8 @@ func (tc *Manager) AppliedResourceUID(id object.ObjMetadata) (types.UID, bool) { func (tc *Manager) AppliedResourceUIDs() sets.String { uids := sets.NewString() for _, objStatus := range tc.inventory.Status.Objects { - if objStatus.Strategy == ActuationStrategyApply && - objStatus.Actuation == ActuationSucceeded { + if objStatus.Strategy == actuation.ActuationStrategyApply && + objStatus.Actuation == actuation.ActuationSucceeded { if objStatus.UID != "" { uids.Insert(string(objStatus.UID)) } @@ -144,8 +145,8 @@ func (tc *Manager) IsSuccessfulDelete(id object.ObjMetadata) bool { if !found { return false } - return objStatus.Strategy == ActuationStrategyDelete && - objStatus.Actuation == ActuationSucceeded + return objStatus.Strategy == actuation.ActuationStrategyDelete && + objStatus.Actuation == actuation.ActuationSucceeded } // AddSuccessfulDelete updates the context with information about the @@ -154,11 +155,11 @@ func (tc *Manager) IsSuccessfulDelete(id object.ObjMetadata) bool { // object was scheduled to be deleted asynchronously, which might cause further // updates by finalizers. The UID will change if the object is re-created. func (tc *Manager) AddSuccessfulDelete(id object.ObjMetadata, uid types.UID) { - tc.SetObjectStatus(id, ObjectStatus{ + tc.SetObjectStatus(id, actuation.ObjectStatus{ ObjectReference: ObjectReferenceFromObjMetadata(id), - Strategy: ActuationStrategyDelete, - Actuation: ActuationSucceeded, - Reconcile: ReconcilePending, + Strategy: actuation.ActuationStrategyDelete, + Actuation: actuation.ActuationSucceeded, + Reconcile: actuation.ReconcilePending, UID: uid, }) } @@ -166,8 +167,8 @@ func (tc *Manager) AddSuccessfulDelete(id object.ObjMetadata, uid types.UID) { // SuccessfulDeletes returns all the objects (as ObjMetadata) that // were successfully deleted. func (tc *Manager) SuccessfulDeletes() object.ObjMetadataSet { - return tc.ObjectsWithActuationStatus(ActuationStrategyDelete, - ActuationSucceeded) + return tc.ObjectsWithActuationStatus(actuation.ActuationStrategyDelete, + actuation.ActuationSucceeded) } // IsFailedApply returns true if the object failed to apply @@ -176,23 +177,23 @@ func (tc *Manager) IsFailedApply(id object.ObjMetadata) bool { if !found { return false } - return objStatus.Strategy == ActuationStrategyApply && - objStatus.Actuation == ActuationFailed + return objStatus.Strategy == actuation.ActuationStrategyApply && + objStatus.Actuation == actuation.ActuationFailed } // AddFailedApply registers that the object failed to apply func (tc *Manager) AddFailedApply(id object.ObjMetadata) { - tc.SetObjectStatus(id, ObjectStatus{ + tc.SetObjectStatus(id, actuation.ObjectStatus{ ObjectReference: ObjectReferenceFromObjMetadata(id), - Strategy: ActuationStrategyApply, - Actuation: ActuationFailed, - Reconcile: ReconcilePending, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationFailed, + Reconcile: actuation.ReconcilePending, }) } // FailedApplies returns all the objects that failed to apply func (tc *Manager) FailedApplies() object.ObjMetadataSet { - return tc.ObjectsWithActuationStatus(ActuationStrategyApply, ActuationFailed) + return tc.ObjectsWithActuationStatus(actuation.ActuationStrategyApply, actuation.ActuationFailed) } // IsFailedDelete returns true if the object failed to delete @@ -201,23 +202,24 @@ func (tc *Manager) IsFailedDelete(id object.ObjMetadata) bool { if !found { return false } - return objStatus.Strategy == ActuationStrategyDelete && - objStatus.Actuation == ActuationFailed + return objStatus.Strategy == actuation.ActuationStrategyDelete && + objStatus.Actuation == actuation.ActuationFailed } // AddFailedDelete registers that the object failed to delete func (tc *Manager) AddFailedDelete(id object.ObjMetadata) { - tc.SetObjectStatus(id, ObjectStatus{ + tc.SetObjectStatus(id, actuation.ObjectStatus{ ObjectReference: ObjectReferenceFromObjMetadata(id), - Strategy: ActuationStrategyDelete, - Actuation: ActuationFailed, - Reconcile: ReconcilePending, + Strategy: actuation.ActuationStrategyDelete, + Actuation: actuation.ActuationFailed, + Reconcile: actuation.ReconcilePending, }) } // FailedDeletes returns all the objects that failed to delete func (tc *Manager) FailedDeletes() object.ObjMetadataSet { - return tc.ObjectsWithActuationStatus(ActuationStrategyDelete, ActuationFailed) + return tc.ObjectsWithActuationStatus(actuation.ActuationStrategyDelete, + actuation.ActuationFailed) } // IsSkippedApply returns true if the object apply was skipped @@ -226,23 +228,23 @@ func (tc *Manager) IsSkippedApply(id object.ObjMetadata) bool { if !found { return false } - return objStatus.Strategy == ActuationStrategyApply && - objStatus.Actuation == ActuationSkipped + return objStatus.Strategy == actuation.ActuationStrategyApply && + objStatus.Actuation == actuation.ActuationSkipped } // AddSkippedApply registers that the object apply was skipped func (tc *Manager) AddSkippedApply(id object.ObjMetadata) { - tc.SetObjectStatus(id, ObjectStatus{ + tc.SetObjectStatus(id, actuation.ObjectStatus{ ObjectReference: ObjectReferenceFromObjMetadata(id), - Strategy: ActuationStrategyApply, - Actuation: ActuationSkipped, - Reconcile: ReconcilePending, + Strategy: actuation.ActuationStrategyApply, + Actuation: actuation.ActuationSkipped, + Reconcile: actuation.ReconcilePending, }) } // SkippedApplies returns all the objects where apply was skipped func (tc *Manager) SkippedApplies() object.ObjMetadataSet { - return tc.ObjectsWithActuationStatus(ActuationStrategyApply, ActuationSkipped) + return tc.ObjectsWithActuationStatus(actuation.ActuationStrategyApply, actuation.ActuationSkipped) } // IsSkippedDelete returns true if the object delete was skipped @@ -251,23 +253,24 @@ func (tc *Manager) IsSkippedDelete(id object.ObjMetadata) bool { if !found { return false } - return objStatus.Strategy == ActuationStrategyDelete && - objStatus.Actuation == ActuationSkipped + return objStatus.Strategy == actuation.ActuationStrategyDelete && + objStatus.Actuation == actuation.ActuationSkipped } // AddSkippedDelete registers that the object delete was skipped func (tc *Manager) AddSkippedDelete(id object.ObjMetadata) { - tc.SetObjectStatus(id, ObjectStatus{ + tc.SetObjectStatus(id, actuation.ObjectStatus{ ObjectReference: ObjectReferenceFromObjMetadata(id), - Strategy: ActuationStrategyDelete, - Actuation: ActuationSkipped, - Reconcile: ReconcilePending, + Strategy: actuation.ActuationStrategyDelete, + Actuation: actuation.ActuationSkipped, + Reconcile: actuation.ReconcilePending, }) } // SkippedDeletes returns all the objects where deletion was skipped func (tc *Manager) SkippedDeletes() object.ObjMetadataSet { - return tc.ObjectsWithActuationStatus(ActuationStrategyDelete, ActuationSkipped) + return tc.ObjectsWithActuationStatus(actuation.ActuationStrategyDelete, + actuation.ActuationSkipped) } // IsSuccessfulReconcile returns true if the object is reconciled @@ -276,7 +279,7 @@ func (tc *Manager) IsSuccessfulReconcile(id object.ObjMetadata) bool { if !found { return false } - return objStatus.Reconcile == ReconcileSucceeded + return objStatus.Reconcile == actuation.ReconcileSucceeded } // SetSuccessfulReconcile registers that the object is reconciled @@ -285,13 +288,13 @@ func (tc *Manager) SetSuccessfulReconcile(id object.ObjMetadata) error { if !found { return fmt.Errorf("object not in inventory: %q", id) } - objStatus.Reconcile = ReconcileSucceeded + objStatus.Reconcile = actuation.ReconcileSucceeded return nil } // SuccessfulReconciles returns all the reconciled objects func (tc *Manager) SuccessfulReconciles() object.ObjMetadataSet { - return tc.ObjectsWithReconcileStatus(ReconcileSucceeded) + return tc.ObjectsWithReconcileStatus(actuation.ReconcileSucceeded) } // IsFailedReconcile returns true if the object failed to reconcile @@ -300,7 +303,7 @@ func (tc *Manager) IsFailedReconcile(id object.ObjMetadata) bool { if !found { return false } - return objStatus.Reconcile == ReconcileFailed + return objStatus.Reconcile == actuation.ReconcileFailed } // SetFailedReconcile registers that the object failed to reconcile @@ -309,13 +312,13 @@ func (tc *Manager) SetFailedReconcile(id object.ObjMetadata) error { if !found { return fmt.Errorf("object not in inventory: %q", id) } - objStatus.Reconcile = ReconcileFailed + objStatus.Reconcile = actuation.ReconcileFailed return nil } // FailedReconciles returns all the objects that failed to reconcile func (tc *Manager) FailedReconciles() object.ObjMetadataSet { - return tc.ObjectsWithReconcileStatus(ReconcileFailed) + return tc.ObjectsWithReconcileStatus(actuation.ReconcileFailed) } // IsSkippedReconcile returns true if the object reconcile was skipped @@ -324,7 +327,7 @@ func (tc *Manager) IsSkippedReconcile(id object.ObjMetadata) bool { if !found { return false } - return objStatus.Reconcile == ReconcileSkipped + return objStatus.Reconcile == actuation.ReconcileSkipped } // SetSkippedReconcile registers that the object reconcile was skipped @@ -333,13 +336,13 @@ func (tc *Manager) SetSkippedReconcile(id object.ObjMetadata) error { if !found { return fmt.Errorf("object not in inventory: %q", id) } - objStatus.Reconcile = ReconcileSkipped + objStatus.Reconcile = actuation.ReconcileSkipped return nil } // SkippedReconciles returns all the objects where reconcile was skipped func (tc *Manager) SkippedReconciles() object.ObjMetadataSet { - return tc.ObjectsWithReconcileStatus(ReconcileSkipped) + return tc.ObjectsWithReconcileStatus(actuation.ReconcileSkipped) } // IsTimeoutReconcile returns true if the object reconcile was skipped @@ -348,7 +351,7 @@ func (tc *Manager) IsTimeoutReconcile(id object.ObjMetadata) bool { if !found { return false } - return objStatus.Reconcile == ReconcileTimeout + return objStatus.Reconcile == actuation.ReconcileTimeout } // SetTimeoutReconcile registers that the object reconcile was skipped @@ -357,13 +360,13 @@ func (tc *Manager) SetTimeoutReconcile(id object.ObjMetadata) error { if !found { return fmt.Errorf("object not in inventory: %q", id) } - objStatus.Reconcile = ReconcileTimeout + objStatus.Reconcile = actuation.ReconcileTimeout return nil } // TimeoutReconciles returns all the objects where reconcile was skipped func (tc *Manager) TimeoutReconciles() object.ObjMetadataSet { - return tc.ObjectsWithReconcileStatus(ReconcileTimeout) + return tc.ObjectsWithReconcileStatus(actuation.ReconcileTimeout) } // IsPendingReconcile returns true if the object reconcile is pending @@ -372,7 +375,7 @@ func (tc *Manager) IsPendingReconcile(id object.ObjMetadata) bool { if !found { return false } - return objStatus.Reconcile == ReconcilePending + return objStatus.Reconcile == actuation.ReconcilePending } // SetPendingReconcile registers that the object reconcile is pending @@ -381,11 +384,11 @@ func (tc *Manager) SetPendingReconcile(id object.ObjMetadata) error { if !found { return fmt.Errorf("object not in inventory: %q", id) } - objStatus.Reconcile = ReconcilePending + objStatus.Reconcile = actuation.ReconcilePending return nil } // PendingReconciles returns all the objects where reconcile is pending func (tc *Manager) PendingReconciles() object.ObjMetadataSet { - return tc.ObjectsWithReconcileStatus(ReconcilePending) + return tc.ObjectsWithReconcileStatus(actuation.ReconcilePending) } diff --git a/pkg/inventory/type-conv.go b/pkg/inventory/type-conv.go index 88c26bc8..d0538b12 100644 --- a/pkg/inventory/type-conv.go +++ b/pkg/inventory/type-conv.go @@ -5,11 +5,12 @@ package inventory import ( "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/cli-utils/pkg/apis/actuation" "sigs.k8s.io/cli-utils/pkg/object" ) // ObjMetadataEqualObjectReference compares an ObjMetadata with a ObjectReference -func ObjMetadataEqualObjectReference(id object.ObjMetadata, ref ObjectReference) bool { +func ObjMetadataEqualObjectReference(id object.ObjMetadata, ref actuation.ObjectReference) bool { return id.GroupKind.Group == ref.Group && id.GroupKind.Kind == ref.Kind && id.Namespace == ref.Namespace && @@ -17,8 +18,8 @@ func ObjMetadataEqualObjectReference(id object.ObjMetadata, ref ObjectReference) } // ObjectReferenceFromObjMetadata converts an ObjMetadata to a ObjectReference -func ObjectReferenceFromObjMetadata(id object.ObjMetadata) ObjectReference { - return ObjectReference{ +func ObjectReferenceFromObjMetadata(id object.ObjMetadata) actuation.ObjectReference { + return actuation.ObjectReference{ Group: id.GroupKind.Group, Kind: id.GroupKind.Kind, Name: id.Name, @@ -27,7 +28,7 @@ func ObjectReferenceFromObjMetadata(id object.ObjMetadata) ObjectReference { } // ObjMetadataFromObjectReference converts an ObjectReference to a ObjMetadata -func ObjMetadataFromObjectReference(ref ObjectReference) object.ObjMetadata { +func ObjMetadataFromObjectReference(ref actuation.ObjectReference) object.ObjMetadata { return object.ObjMetadata{ GroupKind: schema.GroupKind{ Group: ref.Group,